diff --git a/.gitignore b/.gitignore index 26355427d0c02cb281a52bf083e1e847bcdf45bc..2dc24bdd8dcd460f5b1fc498c7fb44c14a407e2d 100644 --- a/.gitignore +++ b/.gitignore @@ -121,6 +121,7 @@ tmp/ # TeXlipse plugin .texlipseXml version="1.0" encoding="UTF-8"?> -gradle.properties +/gradle.properties sign.properties -app/oschina.keystore + +captures/* diff --git a/.inputrc.save b/.inputrc.save new file mode 100644 index 0000000000000000000000000000000000000000..a1ccdf829a99a0222224a5fd4aa7eb499148686a --- /dev/null +++ b/.inputrc.save @@ -0,0 +1,3 @@ +set completion-ignore-case on +set show-all-if-ambiguous on +TAB:menu-complete diff --git a/README.md b/README.md index 997af8c75b136362fddbcaf659619b5b3833fdd2..1b575974f4a7f272cc1df96fdc4175a954d13bc2 100644 --- a/README.md +++ b/README.md @@ -1,47 +1,28 @@ -# OSChina Android [客户端](http://www.oschina.net/app/) +##提示 +- 新版界面实现详见:net.oschina.app.improve包。 +- OSChina Android [客户端](http://www.oschina.net/app/) -##写在前面的话 -从2.3版本开始,项目已经完成了gradle化,完全迁移到了android studio,如果想使用eclipse进行该项目的学习,可以clone [tag v2.2.1](http://git.oschina.net/oschina/android-app/tree/v2.2.1/),不过需要注意的是,eclipse需要按照开发环境中提到的:进行butterknife注解设置 -##开发环境 -由于使用了较多的Eclipse项目Library,项目目前使用的是Eclipse。需要提示的是,由于butterknife注解特性,Eclipse需要开启注解功能,详细方法参考[这里](http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0102/2247.html)。对于使用Android Studio的开发者,可能你们需要等待一段时间,项目目前正在Gradle化。当然,我们也欢迎由你来转换项目并通过PullRequest提交给我们,充分发挥社区化协作的优势。 - -##项目简述 -1. 底部导航 - * 主界面的底部TAB导航采用[FragmentTabHost](http://git.oschina.net/oschina/osc-android-app/blob/master/osc-android-app/src/net/oschina/app/ui/MainTab.java)点击底部按钮时切换Fragment。中间的快捷操作按钮使用的是[自定义dialog](http://git.oschina.net/oschina/osc-android-app/blob/master/osc-android-app/src/net/oschina/app/ui/QuickOptionDialog.java),通过点击时加入动画效果实现。 -2. 一级界面 - * 包括资讯、动弹两个模块,采用[ViewPagerFragment](http://git.oschina.net/oschina/osc-android-app/blob/master/osc-android-app/src/net/oschina/app/viewpagerfragment/NewsViewPagerFragment.java)根据滑动到不同页面显示不同信息。 -3. 详情界面 - * 详情界面包括[博客详情](http://git.oschina.net/oschina/osc-android-app/blob/master/osc-android-app/src/net/oschina/app/fragment/BlogDetailFragment.java),[动弹详情](http://git.oschina.net/oschina/osc-android-app/blob/master/osc-android-app/src/net/oschina/app/fragment/TweetDetailFragment.java),[新闻详情](http://git.oschina.net/oschina/osc-android-app/blob/master/osc-android-app/src/net/oschina/app/fragment/NewsDetailFragment.java),[帖子详情](http://git.oschina.net/oschina/osc-android-app/blob/master/osc-android-app/src/net/oschina/app/fragment/PostDetailFragment.java), [活动详情](http://git.oschina.net/oschina/osc-android-app/blob/master/osc-android-app/src/net/oschina/app/fragment/EventDetailFragment.java)等……是通过在Fragment中的WebView直接loadData()加载一段html数据并显示。 - * 而详情Fragment的显示则是通过一个外部DetailActivity,来根据传入的参数不同来加载不同的Fragment。 -4. 链接跳转 - * 整个应用打开链接的规则都定义在UIHelper.openBrowser()方法中,本方法会根据不同的url去解析,如果是www.oschina.net的链接,则会调用相应的界面去展示;如果是git.oschina.net我们目前会使用手机自带的浏览器打开(之后会改为使用[OscGit客户端](http://git.oschina.net/oschina/git-osc-android-project)打开);如果不是oschina的站内链接,则使用内置浏览器打开。 -5. 侧滑菜单 - * [侧滑菜单](http://git.oschina.net/oschina/osc-android-app/blob/master/osc-android-app/src/net/oschina/app/ui/NavigationDrawerFragment.java)采用系统的DrawerLayout实现。关于很多朋友好奇的左上角箭头,是采用的开源控件[DrawerArrowDrawable](http://git.oschina.net/oschina/osc-android-app/blob/master/osc-android-app/src/net/oschina/app/widget/DrawerArrowDrawable.java)(准确的说不应该是控件而是一个Drawable) +##开源协议 -##依赖包介绍 -1. jar包依赖 - * 网络请求库 **android-async-http** :http://loopj.com/android-async-http/ - * 注解绑定控件 **butterknife** http://jakewharton.github.io/butterknife/ - * 网络图片加载库 **KJFrameForAndroid** http://git.oschina.net/kymjs/KJFrameForAndroid - * XML解析库 **xstream** http://xstream.codehaus.org/ -2. 源码依赖 - * **PhotoView-library** :用于图片预览界面展示 - * **UmengShareLib** :用于分享到第三方平台 + The MIT License (MIT) -##开源协议 - Copyright (C) 2014, The OSChina Open Source Project + Copyright (c) 2016 OSChina.net -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. \ No newline at end of file + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index e540323d6a2a30d1cd9d771716ca9684737cdb62..00ed0ade9094a6a41996ae5c29a933aa052cb9d2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,34 +1,142 @@ apply plugin: 'com.android.application' -apply plugin: 'newlens' +apply from: '../config/properties-util.gradle' android { - compileSdkVersion 23 - buildToolsVersion '21.1.2' + + compileSdkVersion rootProject.ext.compileSdkVersion + buildToolsVersion rootProject.ext.buildToolsVersion defaultConfig { - applicationId "net.oschina.app" - minSdkVersion 15 - targetSdkVersion 23 - versionCode 48 - versionName "2.4.1" + applicationId rootProject.ext.applicationId + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion + versionCode rootProject.ext.versionCode + versionName rootProject.ext.versionName + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + + // rename the apk with the version name + applicationVariants.all { variant -> + variant.outputs.each { output -> + output.outputFile = new File( + output.outputFile.parent + "/${variant.buildType.name}", + "osc-android-${variant.versionName}-${variant.productFlavors[0].name}-${variant.buildType.name}.apk".toLowerCase()) + } + } + + //signing files settings + signingConfigs { + if (propertyHaveSigningConfigs) { + debug { + storeFile file(propertyStoreFileStr) + storePassword propertyStorePwdStr + keyAlias propertyKeyAliasStr + keyPassword propertyKeyPwdStr + } + + release { + storeFile file(propertyStoreFileStr) + storePassword propertyStorePwdStr + keyAlias propertyKeyAliasStr + keyPassword propertyKeyPwdStr + } + } + } + + sourceSets { + main { + jniLibs.srcDirs = ['libs'] + } } // 移除lint检查的error lintOptions { abortOnError false } + + //build type setting + buildTypes { + + debug { + zipAlignEnabled false + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + if (propertyHaveSigningConfigs) + signingConfig signingConfigs.debug + } + + release { + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + zipAlignEnabled true + if (propertyHaveSigningConfigs) + signingConfig signingConfigs.release + } + } + + //product flavors + productFlavors { + oschina { + manifestPlaceholders = [UMENG_CHANNEL: "oschina"] + } + + wandoujia { + manifestPlaceholders = [UMENG_CHANNEL: "wandoujia"] + } + + xiaomi { + manifestPlaceholders = [UMENG_CHANNEL: "xiaomi"] + } + } +} + +repositories { + flatDir { + dirs 'libs' + } + if (propertyHaveDebugCompile) { + maven { + url propertyDebugCompileUrl + } + } } dependencies { + compile "com.android.support:support-v4:$rootProject.ext.supportVersion" + compile "com.android.support:appcompat-v7:$rootProject.ext.supportVersion" + compile "com.android.support:design:$rootProject.ext.supportVersion" + compile "com.android.support:recyclerview-v7:$rootProject.ext.supportVersion" + compile "com.android.support:cardview-v7:$rootProject.ext.supportVersion" + compile fileTree(include: ['*.jar'], dir: 'libs') - compile project(':social_sdk_library_project') - compile 'com.android.support:appcompat-v7:23.1.0' - compile 'com.github.chrisbanes.photoview:library:1.2.3' + compile project(':open') + compile 'com.github.chrisbanes.photoview:library:1.2.4' compile 'com.loopj.android:android-async-http:1.4.9' - compile 'com.jakewharton:butterknife:6.1.0' + compile 'com.jakewharton:butterknife:7.0.1' compile 'org.kymjs.kjframe:kjframe:2.6' - compile 'com.networkbench.newlens.agent.android:nbs.newlens.agent:2.2.7' - compile 'com.google.zxing:core:3.2.0' + compile 'com.google.zxing:core:3.3.0' compile 'com.joanzapata.android:android-iconify:1.0.9' compile 'com.makeramen:roundedimageview:2.1.1' + compile 'pub.devrel:easypermissions:0.1.7' + compile 'com.github.bumptech.glide:glide:3.7.0' + compile 'de.hdodenhof:circleimageview:2.0.0' + compile 'com.google.code.gson:gson:2.8.0' + compile 'net.qiujuer.genius:graphics:2.0.0-beta8' + compile 'net.qiujuer.genius:res:2.0.0-beta8' + compile 'net.qiujuer.genius:ui:2.0.0-beta8' + compile 'com.umeng.analytics:analytics:latest.integration' + compile 'net.oschina.common:common:0.1.0' + + if (propertyHaveDebugCompile) { + compile propertyDebugCompile + } + + androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { + exclude group: 'com.android.support', module: 'support-annotations' + }) + + testCompile 'junit:junit:4.12' } + + +apply plugin: 'com.getkeepsafe.dexcount' \ No newline at end of file diff --git a/app/src/main/jniLibs/armeabi/libzbar.so b/app/libs/armeabi/libzbar.so similarity index 100% rename from app/src/main/jniLibs/armeabi/libzbar.so rename to app/libs/armeabi/libzbar.so diff --git a/app/libs/baidumapapi_v3_2_0.jar b/app/libs/baidumapapi_v3_2_0.jar deleted file mode 100644 index c60212c7633ee1dac18b0cc3292cee99b9bbb290..0000000000000000000000000000000000000000 Binary files a/app/libs/baidumapapi_v3_2_0.jar and /dev/null differ diff --git a/app/libs/locSDK_3.1.jar b/app/libs/locSDK_3.1.jar deleted file mode 100644 index f503848aadcf698ed8c9fe8a04d8bc4dd5de0804..0000000000000000000000000000000000000000 Binary files a/app/libs/locSDK_3.1.jar and /dev/null differ diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 41abe698d28002306c29e2b019aa0c1f06d893e4..50e7b74fa04cac895d4d8d30767580728fe1688d 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -15,3 +15,109 @@ #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} + +##---------------Begin: proguard configuration for Gson ---------- +# Gson uses generic type information stored in a class file when working with fields. Proguard +# removes such information by default, so configure it to keep all of it. +-keepattributes Signature + +# For using GSON @Expose annotation +-keepattributes *Annotation* + +# Gson specific classes +-keep class sun.misc.Unsafe { *; } +#-keep class com.google.gson.stream.** { *; } + +# Application classes that will be serialized/deserialized over Gson +-keep class net.oschina.app.improve.bean.** { *; } + +-keepattributes EnclosingMethod + +##---------------End: proguard configuration for Gson ---------- + +-keep class net.oschina.app.** { *; } +-keep class net.oschina.common.** { *; } + + +-keep class butterknife.** { *; } +-dontwarn butterknife.internal.** +-keep class **$$ViewBinder { *; } + +-keepclasseswithmembernames class * { + @butterknife.* ; +} + +-keepclasseswithmembernames class * { + @butterknife.* ; +} + +-dontwarn com.thoughtworks.xstream.** +-keep class com.thoughtworks.xstream.** { *; } + +-dontwarn com.makeramen.roundedimageview.** +-keep class com.makeramen.roundedimageview.RoundedTransformationBuilder + +-dontwarn com.tencent.weibo.sdk.android.** +-keep class com.tencent.weibo.sdk.android.** { *; } + +-dontwarn com.squareup.leakcanary.DisplayLeakService +-keep class com.squareup.leakcanary.DisplayLeakService + +-dontwarn android.widget.** +-keep class android.widget.** {*;} + +-dontwarn android.support.v7.widget.** +-keep class android.support.v7.widget.**{*;} + +-dontshrink +-dontoptimize +-dontwarn com.google.android.maps.** +-dontwarn android.webkit.WebView +-dontwarn com.tencent.weibo.sdk.** + +-keepattributes Exceptions,InnerClasses,Signature +-keepattributes *Annotation* +-keepattributes SourceFile,LineNumberTable + +-keep public interface com.tencent.** +-keep public class javax.** +-keep public class android.webkit.** +-keep public class com.tencent.** {*;} + +-keep class com.sina.weibo.** {*;} +-keep class net.oschina.open.**{*;} +-keep class com.tencent.mm.sdk.modelmsg.WXMediaMessage {*;} +-keep class com.tencent.mm.sdk.modelmsg.** implements com.tencent.mm.sdk.modelmsg.WXMediaMessage$IMediaObject {*;} + +# Glide Start +-keep public class * implements com.bumptech.glide.module.GlideModule +-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** { + **[] $VALUES; + public *; +} +# Glide End + +#-dontwarn android.net.SSLCertificateSocketFactory + +# 友盟Start +-keepclassmembers class * { + public (org.json.JSONObject); +} +-keep public class net.oschina.app.R$*{ + public static final int *; +} +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} +-dontwarn com.umeng.** +-keep public interface com.umeng.socialize.** +-keep public interface com.umeng.socialize.sensor.** +-keep public interface com.umeng.scrshot.** +-keep public class com.umeng.socialize.* {*;} +-keep class com.umeng.scrshot.** +-keep class com.umeng.socialize.sensor.** +-keep class pub.devrel.easypermissions.** +# 友盟End + +-dontwarn okio.** \ No newline at end of file diff --git a/app/src/androidTest/java/net/oschina/app/ApplicationTest.java b/app/src/androidTest/java/net/oschina/app/OSCApplicationTest.java similarity index 61% rename from app/src/androidTest/java/net/oschina/app/ApplicationTest.java rename to app/src/androidTest/java/net/oschina/app/OSCApplicationTest.java index 5b378ac2dc1f57ad81a454efa7534b4304825e4c..d77f0189ef04de5608350ffe1dcde214a09b0067 100644 --- a/app/src/androidTest/java/net/oschina/app/ApplicationTest.java +++ b/app/src/androidTest/java/net/oschina/app/OSCApplicationTest.java @@ -6,8 +6,14 @@ import android.test.ApplicationTestCase; /** * Testing Fundamentals */ -public class ApplicationTest extends ApplicationTestCase { - public ApplicationTest() { +public class OSCApplicationTest extends ApplicationTestCase { + + public OSCApplicationTest() { super(Application.class); } + + public void testParseUrl(){ + + } + } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2240c7c8d535029f094d51907926d7825e5a57c0..d3f36464abae59d1e04c08202022c39cd8bc16a2 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,12 +1,16 @@ + + + @@ -22,6 +26,11 @@ + + + + + @@ -34,16 +43,17 @@ android:xlargeScreens="true" /> + android:theme="@style/App.Theme.Light" + tools:replace="android:allowBackup"> + android:theme="@style/App.Theme.Launch"> @@ -51,9 +61,215 @@ + + + + + + + + + + + + + + + android:noHistory="true" + android:theme="@style/App.Theme.Tweet.Main"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -96,9 +312,12 @@ + android:name=".improve.tweet.activities.TweetPublishActivity" + android:label="弹一弹" + android:launchMode="singleTask" + android:screenOrientation="portrait" + android:theme="@style/App.Theme.Tweet.Publish" + android:windowSoftInputMode="adjustResize"> @@ -121,127 +340,160 @@ - - - - + + - + + + + android:theme="@style/Account_Base.App.Theme.NoTitle" + android:windowSoftInputMode="stateHidden|adjustResize" /> + + android:label="注册中心二" + android:launchMode="singleTop" + android:screenOrientation="portrait" + android:theme="@style/Account_Base.App.Theme.NoTitle" + android:windowSoftInputMode="stateHidden|adjustResize" /> + + + + - + - - - + android:theme="@style/Theme.Dialog.NoTitle.Translucent" /> - + - + + + + + + - - - - - - - - - - - - - - - - - + - + - - - - - - + android:name=".improve.tweet.service.TweetPublishService" + android:exported="false" + android:process="net.oschina.app.tweet.TweetPublishService" /> - - - - - - + android:name=".improve.notice.NoticeServer" + android:exported="false" + android:process="net.oschina.app.notice.NoticeServer" /> + - - - - - - + - - + - + \ No newline at end of file diff --git a/app/src/main/assets/css/common_detail.css b/app/src/main/assets/css/common_detail.css new file mode 100644 index 0000000000000000000000000000000000000000..63788f6176d2347bf3fbdeb08051940ea0568e03 --- /dev/null +++ b/app/src/main/assets/css/common_detail.css @@ -0,0 +1,68 @@ +html, body { + font-family: -apple-system, "Helvetica Neue", Helvetica, "Nimbus Sans L", Arial, "Liberation Sans", "PingFang SC", "Hiragino Sans GB", "Source Han Sans CN", "Source Han Sans SC", "Microsoft YaHei", "Wenquanyi Micro Hei", "WenQuanYi Zen Hei", "ST Heiti", SimHei, "WenQuanYi Zen Hei Sharp", sans-serif; + padding: 0px; + margin: 0px; + overflow-x: hidden; +} + +body { + word-wrap: break-word; + font-size: 16px; + line-height: 165%; + color: #111111; +} + +.body-content{ + box-pack: justify; + text-justify: inter-ideograph; + text-align: justify; +} + +h1, h2, h3, h4, h5, h6 { + line-height: 1.2em; + margin: 0; + margin-bottom: 0.8em; +} + +p{ + margin: 0; + margin-bottom: 0.8em; +} + +table { + overflow: hidden; + max-width: 100%; + border: 1px solid #CFCDD3; + border-collapse: none; + background: #f8f8f8; + font-size: 0.8em; + margin-right: 1px; +} + +img { + max-width: 100%; + margin: 4px 0; + background: #fefefe; + border: none; + box-shadow: none; +} + +pre { + margin-top: 1px; + margin-bottom: 1px; + font-size: 0.8em; + font-family: monaco, Consolas, 'Liberation Mono', Courier, monospace; + border: none; + border-left: 2px solid #CFCDD3; + background: #f8f8f8; + padding: 8px 6px 6px 6px; + line-height: 140%; + overflow: auto; + word-wrap: break-word; + word-break:break-all; +} + +a { + text-decoration: none; + color: #24cf5f +} \ No newline at end of file diff --git a/app/src/main/assets/css/common_new.css b/app/src/main/assets/css/common_new.css new file mode 100644 index 0000000000000000000000000000000000000000..5bf09dc2a744d29b2a316b40a0f9231f5a7e222f --- /dev/null +++ b/app/src/main/assets/css/common_new.css @@ -0,0 +1,59 @@ +html, body { + padding: 0px; + margin: 0px; + overflow-x: hidden; +} + +body { + word-wrap: break-word; + font-size: 15px; + letter-spacing: 1px; + line-height: 165%; + color: #111111; +} + +.body-content{ + box-pack: justify; + text-justify: inter-ideograph; + text-align: justify; +} + +h1, h2, h3, h4, h5, h6 { + color: #010101; +} + +table { + overflow: hidden; + max-width: 100%; + border: 1px solid #CFCDD3; + border-collapse: none; + background: #f8f8f8; + font-size: 0.8em; + margin-right: 1px; +} + +img { + max-width: 100%; + margin: 4px 0; + background: #fefefe; + border: none; + box-shadow: none; +} + +pre { + margin-top: 1px; + margin-bottom: 1px; + font-size: 0.8em; + font-family: monaco, Consolas, 'Liberation Mono', Courier, monospace; + border: none; + border-left: 2px solid #CFCDD3; + background: #f8f8f8; + padding: 8px 6px 6px 6px; + line-height: 140%; + overflow: auto; +} + +a { + text-decoration: none; + color: #24cf5f +} \ No newline at end of file diff --git a/app/src/main/assets/sub_tab_original.json b/app/src/main/assets/sub_tab_original.json new file mode 100644 index 0000000000000000000000000000000000000000..941435ed281fbc12cfdaf077eed5bccf9ddb8bb3 --- /dev/null +++ b/app/src/main/assets/sub_tab_original.json @@ -0,0 +1,325 @@ +[ + { + "banner": { + "catalog": 1, + "href": "https://www.oschina.net/action/apiv2//banner?catalog=1" + }, + "fixed": true, + "href": "https://www.oschina.net/action/apiv2/sub_list?token=d6112fa662bc4bf21084670a857fbd20", + "name": "开源资讯", + "needLogin": false, + "isActived": true, + "order": 1, + "subtype": 1, + "token": "d6112fa662bc4bf21084670a857fbd20", + "type": 6 + }, + { + "fixed": true, + "href": "https://www.oschina.net/action/apiv2/sub_list?token=df985be3c5d5449f8dfb47e06e098ef9", + "name": "推荐博客", + "needLogin": false, + "isActived": true, + "order": 3, + "subtype": 4, + "token": "df985be3c5d5449f8dfb47e06e098ef9", + "type": 3 + }, + { + "fixed": true, + "href": "https://www.oschina.net/action/apiv2/sub_list?token=98d04eb58a1d12b75d254deecbc83790", + "name": "技术问答", + "needLogin": false, + "isActived": true, + "order": 2, + "subtype": 3, + "token": "98d04eb58a1d12b75d254deecbc83790", + "type": 2 + }, + { + "fixed": true, + "href": "https://www.oschina.net/action/apiv2/sub_list?token=1abf09a23a87442184c2f9bf9dc29e35", + "name": "每日一博", + "needLogin": false, + "isActived": true, + "order": 4, + "subtype": 1, + "token": "1abf09a23a87442184c2f9bf9dc29e35", + "type": 3 + }, + { + "fixed": false, + "href": "https://www.oschina.net/action/apiv2/sub_list?token=299975006aa7f9b8a158deeb0d27a011", + "name": "码云推荐", + "needLogin": false, + "isActived": false, + "order": 70, + "subtype": 1, + "token": "299975006aa7f9b8a158deeb0d27a011", + "type": 7 + }, + { + "fixed": false, + "href": "https://www.oschina.net/action/apiv2/sub_list?token=e3e35d14a62b4f816ec878b6597b60aa", + "name": "热门资讯", + "needLogin": false, + "isActived": false, + "order": 71, + "subtype": 2, + "token": "e3e35d14a62b4f816ec878b6597b60aa", + "type": 6 + }, + { + "fixed": false, + "href": "https://www.oschina.net/action/apiv2/sub_list?token=177f171d41bb37d80c67bee14123f7e1", + "name": "最新翻译", + "needLogin": false, + "isActived": false, + "order": 74, + "subtype": 1, + "token": "177f171d41bb37d80c67bee14123f7e1", + "type": 4 + }, + { + "fixed": false, + "href": "https://www.oschina.net/action/apiv2/sub_list?token=5718df855db5913f25cab8ee4f7c656c", + "name": "移动开发", + "needLogin": false, + "isActived": false, + "order": 75, + "subtype": 18, + "token": "5718df855db5913f25cab8ee4f7c656c", + "type": 3 + }, + { + "fixed": false, + "href": "https://www.oschina.net/action/apiv2/sub_list?token=7975ce15d909bb61a6b85b9392db6149", + "name": "开源硬件", + "needLogin": false, + "isActived": false, + "order": 76, + "subtype": 17, + "token": "7975ce15d909bb61a6b85b9392db6149", + "type": 3 + }, + { + "fixed": false, + "href": "https://www.oschina.net/action/apiv2/sub_list?token=99838268b3bc311a2e763a6a2c4bb9ec", + "name": "云计算", + "needLogin": false, + "isActived": false, + "order": 77, + "subtype": 16, + "token": "99838268b3bc311a2e763a6a2c4bb9ec", + "type": 3 + }, + { + "fixed": false, + "href": "https://www.oschina.net/action/apiv2/sub_list?token=ce53a71a371867582eb3023415c83489", + "name": "软件工程", + "needLogin": false, + "isActived": false, + "order": 78, + "subtype": 15, + "token": "ce53a71a371867582eb3023415c83489", + "type": 3 + }, + { + "fixed": false, + "href": "https://www.oschina.net/action/apiv2/sub_list?token=253b519335b59c011b6db7d1165932bf", + "name": "系统运维", + "needLogin": false, + "isActived": false, + "order": 79, + "subtype": 14, + "token": "253b519335b59c011b6db7d1165932bf", + "type": 3 + }, + { + "fixed": false, + "href": "https://www.oschina.net/action/apiv2/sub_list?token=ad0f1d9e413aeadde89eb899817edd81", + "name": "图像多媒体", + "needLogin": false, + "isActived": false, + "order": 80, + "subtype": 13, + "token": "ad0f1d9e413aeadde89eb899817edd81", + "type": 3 + }, + { + "fixed": false, + "href": "https://www.oschina.net/action/apiv2/sub_list?token=1d76f396e1aad15cf167754bfba9ca78", + "name": "企业开发", + "needLogin": false, + "isActived": false, + "order": 81, + "subtype": 12, + "token": "1d76f396e1aad15cf167754bfba9ca78", + "type": 3 + }, + { + "fixed": false, + "href": "https://www.oschina.net/action/apiv2/sub_list?token=471587b6f0a943f4d675281fa5d13975", + "name": "数据库", + "needLogin": false, + "isActived": false, + "order": 82, + "subtype": 11, + "token": "471587b6f0a943f4d675281fa5d13975", + "type": 3 + }, + { + "fixed": false, + "href": "https://www.oschina.net/action/apiv2/sub_list?token=285cfaccd55f60ebc919d30ad709c6b4", + "name": "编程语言", + "needLogin": false, + "isActived": false, + "order": 83, + "subtype": 10, + "token": "285cfaccd55f60ebc919d30ad709c6b4", + "type": 3 + }, + { + "fixed": false, + "href": "https://www.oschina.net/action/apiv2/sub_list?token=5ca68e0307f68ccd2d181b07d45b110b", + "name": "游戏开发", + "needLogin": false, + "isActived": false, + "order": 84, + "subtype": 9, + "token": "5ca68e0307f68ccd2d181b07d45b110b", + "type": 3 + }, + { + "fixed": false, + "href": "https://www.oschina.net/action/apiv2/sub_list?token=32704cb501253b0422544fd84b7de35b", + "name": "服务端开发", + "needLogin": false, + "isActived": false, + "order": 85, + "subtype": 8, + "token": "32704cb501253b0422544fd84b7de35b", + "type": 3 + }, + { + "fixed": false, + "href": "https://www.oschina.net/action/apiv2/sub_list?token=1299ab1d9f2981cf6100083e106aa531", + "name": "前端开发", + "needLogin": false, + "isActived": false, + "order": 86, + "subtype": 7, + "token": "1299ab1d9f2981cf6100083e106aa531", + "type": 3 + }, + { + "fixed": false, + "href": "https://www.oschina.net/action/apiv2/sub_list?token=63697c05f04140b1ca1dba8e0822ebf4", + "name": "源创君", + "needLogin": false, + "isActived": false, + "order": 87, + "subtype": 6, + "token": "63697c05f04140b1ca1dba8e0822ebf4", + "type": 3 + }, + { + "fixed": false, + "href": "https://www.oschina.net/action/apiv2/sub_list?token=0048958a909973b5d83a8eca65d90afb", + "name": "最新博客", + "needLogin": false, + "isActived": false, + "order": 90, + "subtype": 3, + "token": "0048958a909973b5d83a8eca65d90afb", + "type": 3 + }, + { + "fixed": false, + "href": "https://www.oschina.net/action/apiv2/sub_list?token=b5a06540fdf8d2d4de5c40775585a188", + "name": "热门博客", + "needLogin": false, + "isActived": false, + "order": 91, + "subtype": 2, + "token": "b5a06540fdf8d2d4de5c40775585a188", + "type": 3 + }, + { + "fixed": false, + "href": "https://www.oschina.net/action/apiv2/sub_list?token=2953c7a3d4ebfbae2c45fd34698a6545", + "name": "站务建议", + "needLogin": false, + "isActived": false, + "order": 93, + "subtype": 7, + "token": "2953c7a3d4ebfbae2c45fd34698a6545", + "type": 2 + }, + { + "fixed": false, + "href": "https://www.oschina.net/action/apiv2/sub_list?token=ce1231d4a15c3d1e944943a6aa54d695", + "name": "职业生涯", + "needLogin": false, + "isActived": false, + "order": 94, + "subtype": 6, + "token": "ce1231d4a15c3d1e944943a6aa54d695", + "type": 2 + }, + { + "fixed": false, + "href": "https://www.oschina.net/action/apiv2/sub_list?token=44fe8b07756796cf620dbd18a4cd56e1", + "name": "行业杂烩", + "needLogin": false, + "isActived": false, + "order": 95, + "subtype": 5, + "token": "44fe8b07756796cf620dbd18a4cd56e1", + "type": 2 + }, + { + "fixed": false, + "href": "https://www.oschina.net/action/apiv2/sub_list?token=b56759c46cb81192b7d1cbb1a478a45d", + "name": "技术分享", + "needLogin": false, + "isActived": false, + "order": 96, + "subtype": 4, + "token": "b56759c46cb81192b7d1cbb1a478a45d", + "type": 2 + }, + { + "fixed": false, + "href": "https://www.oschina.net/action/apiv2/sub_list?token=8f7029b477abf806b1125aff3a666e80", + "name": "开源访谈", + "needLogin": false, + "isActived": false, + "order": 98, + "subtype": 2, + "token": "8f7029b477abf806b1125aff3a666e80", + "type": 2 + }, + { + "fixed": false, + "href": "https://www.oschina.net/action/apiv2/sub_list?token=8ebb873ebbdb5f60d33db3f7dd15d63b", + "name": "高手问答", + "needLogin": false, + "isActived": false, + "order": 99, + "subtype": 1, + "token": "8ebb873ebbdb5f60d33db3f7dd15d63b", + "type": 2 + }, + { + "fixed": false, + "href": "https://www.oschina.net/action/apiv2/sub_list?token=b4ca1962b3a80823c6138441015d9836", + "name": "最新软件", + "needLogin": false, + "isActived": false, + "order": 100, + "subtype": 1, + "token": "b4ca1962b3a80823c6138441015d9836", + "type": 1 + } +] diff --git a/app/src/main/java/com/dtr/zxing/activity/CaptureActivity.java b/app/src/main/java/com/dtr/zxing/activity/CaptureActivity.java index abc909303f7cb5db7ba4568f91290791fd6108fa..c7844c47e2ca82487cdb21c23edf01375be7df26 100644 --- a/app/src/main/java/com/dtr/zxing/activity/CaptureActivity.java +++ b/app/src/main/java/com/dtr/zxing/activity/CaptureActivity.java @@ -15,13 +15,14 @@ */ package com.dtr.zxing.activity; +import android.Manifest; import android.annotation.SuppressLint; -import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.graphics.Rect; import android.os.Bundle; import android.os.Handler; +import android.support.annotation.NonNull; import android.text.ClipboardManager; import android.util.Log; import android.view.SurfaceHolder; @@ -33,7 +34,7 @@ import android.view.animation.Animation; import android.view.animation.TranslateAnimation; import android.widget.ImageView; import android.widget.RelativeLayout; -import cz.msebera.android.httpclient.Header; +import android.widget.Toast; import com.dtr.zxing.camera.CameraManager; import com.dtr.zxing.decode.DecodeThread; @@ -51,14 +52,20 @@ import net.oschina.app.base.BaseActivity; import net.oschina.app.bean.BarCode; import net.oschina.app.bean.ResultBean; import net.oschina.app.bean.SingInResult; -import net.oschina.app.util.DialogHelp; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.detail.activities.EventSigninActivity; +import net.oschina.app.improve.utils.DialogHelper; import net.oschina.app.util.StringUtils; import net.oschina.app.util.UIHelper; import net.oschina.app.util.XmlUtils; - import java.io.IOException; import java.lang.reflect.Field; +import java.util.List; + +import cz.msebera.android.httpclient.Header; +import pub.devrel.easypermissions.AfterPermissionGranted; +import pub.devrel.easypermissions.EasyPermissions; /** * This activity opens the camera and does the actual scanning on a background @@ -70,7 +77,7 @@ import java.lang.reflect.Field; * @author Sean Owen */ public final class CaptureActivity extends BaseActivity implements - SurfaceHolder.Callback { + SurfaceHolder.Callback, EasyPermissions.PermissionCallbacks { private static final String TAG = CaptureActivity.class.getSimpleName(); @@ -87,16 +94,6 @@ public final class CaptureActivity extends BaseActivity implements private Rect mCropRect = null; - public Handler getHandler() { - return handler; - } - - public CameraManager getCameraManager() { - return cameraManager; - } - - private boolean isHasSurface = false; - @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); @@ -106,66 +103,28 @@ public final class CaptureActivity extends BaseActivity implements setContentView(R.layout.activity_qr_scan); scanPreview = (SurfaceView) findViewById(R.id.capture_preview); - scanContainer = (RelativeLayout) findViewById(R.id.capture_container); - scanCropView = (RelativeLayout) findViewById(R.id.capture_crop_view); - scanLine = (ImageView) findViewById(R.id.capture_scan_line); - mFlash = (ImageView) findViewById(R.id.capture_flash); - mFlash.setOnClickListener(this); - - inactivityTimer = new InactivityTimer(this); - beepManager = new BeepManager(this); - - TranslateAnimation animation = new TranslateAnimation( - Animation.RELATIVE_TO_PARENT, 0.0f, - Animation.RELATIVE_TO_PARENT, 0.0f, - Animation.RELATIVE_TO_PARENT, 0.0f, - Animation.RELATIVE_TO_PARENT, 0.9f); - animation.setDuration(4500); - animation.setRepeatCount(-1); - animation.setRepeatMode(Animation.RESTART); - scanLine.startAnimation(animation); - } - - @SuppressLint("NewApi") - @Override - protected boolean hasActionBar() { - - if (android.os.Build.VERSION.SDK_INT >= 11) { - getSupportActionBar().hide(); - return true; - } else { - return false; - } + // Install the callback and wait for surfaceCreated() to init the + // camera. + scanPreview.getHolder().addCallback(this); + cameraTask(); } @Override protected void onResume() { - super.onResume(); - - // CameraManager must be initialized here, not in onCreate(). This is - // necessary because we don't - // want to open the camera driver and measure the screen size if we're - // going to show the help on - // first launch. That led to bugs where the scanning rectangle was the - // wrong size and partially - // off screen. - cameraManager = new CameraManager(getApplication()); - - handler = null; - - if (isHasSurface) { - // The activity was paused but not stopped, so the surface still - // exists. Therefore - // surfaceCreated() won't be called, so init the camera here. - initCamera(scanPreview.getHolder()); - } else { - // Install the callback and wait for surfaceCreated() to init the - // camera. - scanPreview.getHolder().addCallback(this); + if (scanPreview != null) { + handler = null; + if (isHasSurface) { + // The activity was paused but not stopped, so the surface still + // exists. Therefore + // surfaceCreated() won't be called, so init the camera here. + initCamera(scanPreview.getHolder()); + } } - - inactivityTimer.onResume(); + if (inactivityTimer != null) { + inactivityTimer.onResume(); + } + super.onResume(); } @Override @@ -174,31 +133,57 @@ public final class CaptureActivity extends BaseActivity implements handler.quitSynchronously(); handler = null; } - inactivityTimer.onPause(); - beepManager.close(); - cameraManager.closeDriver(); - if (!isHasSurface) { - scanPreview.getHolder().removeCallback(this); + if (inactivityTimer != null) { + inactivityTimer.onPause(); + } + if (beepManager != null) { + beepManager.close(); + } + if (cameraManager != null) { + cameraManager.closeDriver(); } super.onPause(); } @Override protected void onDestroy() { - inactivityTimer.shutdown(); + if (inactivityTimer != null) { + inactivityTimer.shutdown(); + } + if (scanPreview != null) { + scanPreview.getHolder().removeCallback(this); + } super.onDestroy(); } + public Handler getHandler() { + return handler; + } + + public CameraManager getCameraManager() { + return cameraManager; + } + + private boolean isHasSurface = false; + + @SuppressLint("NewApi") + @Override + protected boolean hasActionBar() { + if (android.os.Build.VERSION.SDK_INT >= 11) { + getSupportActionBar().hide(); + return true; + } else { + return false; + } + } + @Override public void surfaceCreated(SurfaceHolder holder) { if (holder == null) { - Log.e(TAG, - "*** WARNING *** surfaceCreated() gave us a null surface!"); - } - if (!isHasSurface) { - isHasSurface = true; - initCamera(holder); + Log.e(TAG, "*** WARNING *** surfaceCreated() gave us a null surface!"); } + isHasSurface = true; + initCamera(holder); } @Override @@ -209,7 +194,7 @@ public final class CaptureActivity extends BaseActivity implements @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { - + // Doing } /** @@ -224,12 +209,12 @@ public final class CaptureActivity extends BaseActivity implements beepManager.playBeepSoundAndVibrate(); // 通过这种方式可以获取到扫描的图片 -// bundle.putInt("width", mCropRect.width()); -// bundle.putInt("height", mCropRect.height()); -// bundle.putString("result", rawResult.getText()); -// -// startActivity(new Intent(CaptureActivity.this, ResultActivity.class) -// .putExtras(bundle)); + // bundle.putInt("width", mCropRect.width()); + // bundle.putInt("height", mCropRect.height()); + // bundle.putString("result", rawResult.getText()); + // + // startActivity(new Intent(CaptureActivity.this, ResultActivity.class) + // .putExtras(bundle)); handler.postDelayed(new Runnable() { @@ -254,12 +239,21 @@ public final class CaptureActivity extends BaseActivity implements showConfirmLogin(url); return; } + + if (url.contains("www.oschina.net/event/signin?event")) { + long sourceId = Long.valueOf(url.substring(url.indexOf("=") + 1));//2192570;2193441 + EventSigninActivity.show(CaptureActivity.this, sourceId); + finish(); + return; + } + if (url.contains("oschina.net")) { UIHelper.showUrlRedirect(CaptureActivity.this, url); finish(); return; } - DialogHelp.getConfirmDialog(this, "可能存在风险,是否打开链接?
" + url, new DialogInterface.OnClickListener() { + + DialogHelper.getConfirmDialog(this, "可能存在风险,是否打开链接?\n" + url, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { UIHelper.showUrlRedirect(CaptureActivity.this, url); @@ -274,11 +268,11 @@ public final class CaptureActivity extends BaseActivity implements } private void showConfirmLogin(final String url) { - if (!AppContext.getInstance().isLogin()) { + if (!AccountHelper.isLogin()) { showLogin(); return; } - DialogHelp.getConfirmDialog(this, "扫描成功,是否进行网页登陆", new DialogInterface.OnClickListener() { + DialogHelper.getConfirmDialog(this, "扫描成功,是否进行网页登陆", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { handleScanLogin(url); @@ -357,7 +351,7 @@ public final class CaptureActivity extends BaseActivity implements } private void handleSignIn(BarCode barCode) { - if (barCode.isRequireLogin() && !AppContext.getInstance().isLogin()) { + if (barCode.isRequireLogin() && !AccountHelper.isLogin()) { showLogin(); return; } @@ -368,9 +362,9 @@ public final class CaptureActivity extends BaseActivity implements try { SingInResult res = SingInResult.parse(new String(arg2)); if (res.isOk()) { - DialogHelp.getMessageDialog(CaptureActivity.this, res.getMessage()).show(); + DialogHelper.getMessageDialog(CaptureActivity.this, res.getMessage()).show(); } else { - DialogHelp.getMessageDialog(CaptureActivity.this, res.getErrorMes()).show(); + DialogHelper.getMessageDialog(CaptureActivity.this, res.getErrorMes()).show(); } } catch (AppException e) { e.printStackTrace(); @@ -382,7 +376,7 @@ public final class CaptureActivity extends BaseActivity implements public void onFailure(int arg0, Header[] arg1, byte[] arg2, Throwable arg3) { hideWaitDialog(); - DialogHelp.getMessageDialog(CaptureActivity.this, arg3.getMessage()).show(); + DialogHelper.getMessageDialog(CaptureActivity.this, arg3.getMessage()).show(); } @Override @@ -391,11 +385,11 @@ public final class CaptureActivity extends BaseActivity implements hideWaitDialog(); } }; - OSChinaApi.singnIn(barCode.getUrl(), handler); + OSChinaApi.signin(barCode.getUrl(), handler); } private void showLogin() { - DialogHelp.getConfirmDialog(this, "请先登录,再进行", new DialogInterface.OnClickListener() { + DialogHelper.getConfirmDialog(this, "请先登录,再进行", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { UIHelper.showLoginActivity(CaptureActivity.this); @@ -404,7 +398,7 @@ public final class CaptureActivity extends BaseActivity implements } private void showCopyTextOption(final String text) { - DialogHelp.getConfirmDialog(this, text, new DialogInterface.OnClickListener() { + DialogHelper.getConfirmDialog(this, text, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { ClipboardManager cbm = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); @@ -421,6 +415,9 @@ public final class CaptureActivity extends BaseActivity implements } private void initCamera(SurfaceHolder surfaceHolder) { + if (cameraManager == null) + return; + if (surfaceHolder == null) { throw new IllegalStateException("No SurfaceHolder provided"); } @@ -439,36 +436,14 @@ public final class CaptureActivity extends BaseActivity implements } initCrop(); - } catch (IOException ioe) { - Log.w(TAG, ioe); - displayFrameworkBugMessageAndExit(); - } catch (RuntimeException e) { + } catch (IOException | RuntimeException e) { Log.w(TAG, "Unexpected error initializing camera", e); displayFrameworkBugMessageAndExit(); } } private void displayFrameworkBugMessageAndExit() { - // camera error - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(getString(R.string.app_name)); - builder.setMessage("相机打开出错,请稍后重试"); - builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - finish(); - } - - }); - builder.setOnCancelListener(new DialogInterface.OnCancelListener() { - - @Override - public void onCancel(DialogInterface dialog) { - finish(); - } - }); - builder.show(); + Toast.makeText(this, R.string.permissions_camera_error, Toast.LENGTH_LONG).show(); } public void restartPreviewAfterDelay(long delayMS) { @@ -484,6 +459,7 @@ public final class CaptureActivity extends BaseActivity implements /** * 初始化截取的矩形区域 */ + @SuppressWarnings("SuspiciousNameCombination") private void initCrop() { int cameraWidth = cameraManager.getCameraResolution().y; int cameraHeight = cameraManager.getCameraResolution().x; @@ -531,42 +507,102 @@ public final class CaptureActivity extends BaseActivity implements @Override public void onClick(View v) { - // TODO Auto-generated method stub switch (v.getId()) { case R.id.capture_flash: light(); break; - default: break; } } - private boolean flag; + private boolean mIsLight; - protected void light() { - if (flag == true) { - flag = false; - // 开闪光灯 - cameraManager.openLight(); - mFlash.setBackgroundResource(R.drawable.flash_open); - } else { - flag = true; - // 关闪光灯 - cameraManager.offLight(); - mFlash.setBackgroundResource(R.drawable.flash_default); + private void light() { + try { + if (mIsLight) { + // 关闪光灯 + cameraManager.offLight(); + mFlash.setBackgroundResource(R.mipmap.flash_default); + mIsLight = false; + } else { + // 开闪光灯 + cameraManager.openLight(); + mFlash.setBackgroundResource(R.mipmap.flash_open); + mIsLight = true; + } + } catch (Exception e) { + e.printStackTrace(); } } @Override public void initView() { - // TODO Auto-generated method stub - } @Override public void initData() { - // TODO Auto-generated method stub + } + + private void initCamera() { + scanContainer = (RelativeLayout) findViewById(R.id.capture_container); + scanCropView = (RelativeLayout) findViewById(R.id.capture_crop_view); + scanLine = (ImageView) findViewById(R.id.capture_scan_line); + mFlash = (ImageView) findViewById(R.id.capture_flash); + mFlash.setOnClickListener(this); + + inactivityTimer = new InactivityTimer(this); + beepManager = new BeepManager(this); + + TranslateAnimation animation = new TranslateAnimation( + Animation.RELATIVE_TO_PARENT, 0.0f, + Animation.RELATIVE_TO_PARENT, 0.0f, + Animation.RELATIVE_TO_PARENT, 0.0f, + Animation.RELATIVE_TO_PARENT, 0.9f); + animation.setDuration(4500); + animation.setRepeatCount(-1); + animation.setRepeatMode(Animation.RESTART); + scanLine.startAnimation(animation); + + cameraManager = new CameraManager(getApplication()); + } + + + @Override + public void onPermissionsGranted(int requestCode, List perms) { + if (perms != null && perms.size() == 2) { + initCamera(); + } else { + displayFrameworkBugMessageAndExit(); + } + } + @Override + public void onPermissionsDenied(int requestCode, List perms) { + displayFrameworkBugMessageAndExit(); + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + + // EasyPermissions handles the request result. + EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); + } + + + private static final int CAMERA_PERM = 1; + + @AfterPermissionGranted(CAMERA_PERM) + private void cameraTask() { + String[] perms = {Manifest.permission.CAMERA, Manifest.permission.VIBRATE}; + if (EasyPermissions.hasPermissions(this, perms)) { + initCamera(); + } else { + // Request one permission + EasyPermissions.requestPermissions(this, + getResources().getString(R.string.str_request_camera_message), + CAMERA_PERM, perms); + } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/fourmob/datetimepicker/date/DatePickerDialog.java b/app/src/main/java/com/fourmob/datetimepicker/date/DatePickerDialog.java index 7d862a3db2c0823c94d19ee2dd79054294295c4d..d8c89aeaac59658edc783d1d00fef50d2fd9d910 100644 --- a/app/src/main/java/com/fourmob/datetimepicker/date/DatePickerDialog.java +++ b/app/src/main/java/com/fourmob/datetimepicker/date/DatePickerDialog.java @@ -1,13 +1,5 @@ package com.fourmob.datetimepicker.date; -import java.text.DateFormatSymbols; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Locale; - -import net.oschina.app.R; import android.app.Activity; import android.os.Bundle; import android.os.SystemClock; @@ -26,11 +18,19 @@ import android.widget.TextView; import com.nineoldandroids.animation.ObjectAnimator; +import net.oschina.app.R; + +import java.text.DateFormatSymbols; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Locale; + /** * 摘取自https://github.com/flavienlaurent/datetimepicker - * + * * @author kymjs - * */ public class DatePickerDialog extends DialogFragment implements View.OnClickListener, DatePickerController { @@ -130,47 +130,47 @@ public class DatePickerDialog extends DialogFragment implements private void setCurrentView(int currentView, boolean forceRefresh) { long timeInMillis = mCalendar.getTimeInMillis(); switch (currentView) { - case MONTH_AND_DAY_VIEW: - ObjectAnimator monthDayAnim = Utils.getPulseAnimator( - mMonthAndDayView, 0.9F, 1.05F); - if (mDelayAnimation) { - monthDayAnim.setStartDelay(ANIMATION_DELAY); - mDelayAnimation = false; - } - mDayPickerView.onDateChanged(); - if (mCurrentView != currentView || forceRefresh) { - mMonthAndDayView.setSelected(true); - mYearView.setSelected(false); - mAnimator.setDisplayedChild(MONTH_AND_DAY_VIEW); - mCurrentView = currentView; - } - monthDayAnim.start(); - String monthDayDesc = DateUtils.formatDateTime(getActivity(), - timeInMillis, DateUtils.FORMAT_SHOW_DATE); - mAnimator.setContentDescription(mDayPickerDescription + ": " - + monthDayDesc); - Utils.tryAccessibilityAnnounce(mAnimator, mSelectDay); - break; - case YEAR_VIEW: - ObjectAnimator yearAnim = Utils.getPulseAnimator(mYearView, 0.85F, - 1.1F); - if (mDelayAnimation) { - yearAnim.setStartDelay(ANIMATION_DELAY); - mDelayAnimation = false; - } - mYearPickerView.onDateChanged(); - if (mCurrentView != currentView || forceRefresh) { - mMonthAndDayView.setSelected(false); - mYearView.setSelected(true); - mAnimator.setDisplayedChild(YEAR_VIEW); - mCurrentView = currentView; - } - yearAnim.start(); - String dayDesc = YEAR_FORMAT.format(timeInMillis); - mAnimator.setContentDescription(mYearPickerDescription + ": " - + dayDesc); - Utils.tryAccessibilityAnnounce(mAnimator, mSelectYear); - break; + case MONTH_AND_DAY_VIEW: + ObjectAnimator monthDayAnim = Utils.getPulseAnimator( + mMonthAndDayView, 0.9F, 1.05F); + if (mDelayAnimation) { + monthDayAnim.setStartDelay(ANIMATION_DELAY); + mDelayAnimation = false; + } + mDayPickerView.onDateChanged(); + if (mCurrentView != currentView || forceRefresh) { + mMonthAndDayView.setSelected(true); + mYearView.setSelected(false); + mAnimator.setDisplayedChild(MONTH_AND_DAY_VIEW); + mCurrentView = currentView; + } + monthDayAnim.start(); + String monthDayDesc = DateUtils.formatDateTime(getActivity(), + timeInMillis, DateUtils.FORMAT_SHOW_DATE); + mAnimator.setContentDescription(mDayPickerDescription + ": " + + monthDayDesc); + Utils.tryAccessibilityAnnounce(mAnimator, mSelectDay); + break; + case YEAR_VIEW: + ObjectAnimator yearAnim = Utils.getPulseAnimator(mYearView, 0.85F, + 1.1F); + if (mDelayAnimation) { + yearAnim.setStartDelay(ANIMATION_DELAY); + mDelayAnimation = false; + } + mYearPickerView.onDateChanged(); + if (mCurrentView != currentView || forceRefresh) { + mMonthAndDayView.setSelected(false); + mYearView.setSelected(true); + mAnimator.setDisplayedChild(YEAR_VIEW); + mCurrentView = currentView; + } + yearAnim.start(); + String dayDesc = YEAR_FORMAT.format(timeInMillis); + mAnimator.setContentDescription(mYearPickerDescription + ": " + + dayDesc); + Utils.tryAccessibilityAnnounce(mAnimator, mSelectYear); + break; } } @@ -245,7 +245,7 @@ public class DatePickerDialog extends DialogFragment implements } public void initialize(OnDateSetListener onDateSetListener, int year, - int month, int day, boolean vibrate) { + int month, int day, boolean vibrate) { if (year > MAX_YEAR) throw new IllegalArgumentException("year end must < " + MAX_YEAR); if (year < MIN_YEAR) @@ -266,6 +266,7 @@ public class DatePickerDialog extends DialogFragment implements setCurrentView(MONTH_AND_DAY_VIEW); } + @SuppressWarnings("WrongConstant") @Override public void onCreate(Bundle bundle) { super.onCreate(bundle); @@ -284,12 +285,12 @@ public class DatePickerDialog extends DialogFragment implements @Override public View onCreateView(LayoutInflater layoutInflater, ViewGroup parent, - Bundle bundle) { + Bundle bundle) { getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE); View view = layoutInflater.inflate(R.layout.date_picker_dialog, null); - mDayOfWeekView = ((TextView) view.findViewById(R.id.date_picker_header)); + mDayOfWeekView = null; //这个布局没在View中怎么寻找的?((TextView) view.findViewById(R.id.date_picker_header)); mMonthAndDayView = ((LinearLayout) view .findViewById(R.id.date_picker_month_and_day)); mMonthAndDayView.setOnClickListener(this); @@ -472,6 +473,6 @@ public class DatePickerDialog extends DialogFragment implements public static abstract interface OnDateSetListener { public abstract void onDateSet(DatePickerDialog datePickerDialog, - int year, int month, int day); + int year, int month, int day); } } \ No newline at end of file diff --git a/app/src/main/java/net/oschina/app/AppConfig.java b/app/src/main/java/net/oschina/app/AppConfig.java index f6cf28166feb3c74019c7742fda10bb67fce9623..f440e08829129a51c335235f6a79e7a3b9e03b35 100644 --- a/app/src/main/java/net/oschina/app/AppConfig.java +++ b/app/src/main/java/net/oschina/app/AppConfig.java @@ -1,9 +1,9 @@ package net.oschina.app; import android.content.Context; -import android.content.SharedPreferences; import android.os.Environment; -import android.preference.PreferenceManager; + +import net.oschina.common.utils.StreamUtil; import java.io.File; import java.io.FileInputStream; @@ -11,37 +11,17 @@ import java.io.FileOutputStream; import java.util.Properties; /** - * 应用程序配置类:用于保存用户相关信息及设置 - * - * @author FireAnt(http://my.oschina.net/LittleDY) - * @created 2014年9月25日 下午5:29:00 - * + * 应用程序配置类 + * 用于保存用户相关信息及设置 */ public class AppConfig { - private final static String APP_CONFIG = "config"; - - public final static String CONF_COOKIE = "cookie"; - public final static String CONF_APP_UNIQUEID = "APP_UNIQUEID"; - public static final String KEY_LOAD_IMAGE = "KEY_LOAD_IMAGE"; - public static final String KEY_NOTIFICATION_ACCEPT = "KEY_NOTIFICATION_ACCEPT"; - public static final String KEY_NOTIFICATION_SOUND = "KEY_NOTIFICATION_SOUND"; - public static final String KEY_NOTIFICATION_VIBRATION = "KEY_NOTIFICATION_VIBRATION"; public static final String KEY_NOTIFICATION_DISABLE_WHEN_EXIT = "KEY_NOTIFICATION_DISABLE_WHEN_EXIT"; public static final String KEY_CHECK_UPDATE = "KEY_CHECK_UPDATE"; public static final String KEY_DOUBLE_CLICK_EXIT = "KEY_DOUBLE_CLICK_EXIT"; - public static final String KEY_TWEET_DRAFT = "KEY_TWEET_DRAFT"; - public static final String KEY_NOTE_DRAFT = "KEY_NOTE_DRAFT"; - - public static final String KEY_FRITST_START = "KEY_FRIST_START"; - - public static final String KEY_NIGHT_MODE_SWITCH="night_mode_switch"; - - public static final String APP_QQ_KEY = "100942993"; - // 默认存放图片的路径 public final static String DEFAULT_SAVE_IMAGE_PATH = Environment .getExternalStorageDirectory() @@ -67,13 +47,6 @@ public class AppConfig { return appConfig; } - /** - * 获取Preference设置 - */ - public static SharedPreferences getSharedPreferences(Context context) { - return PreferenceManager.getDefaultSharedPreferences(context); - } - public String get(String key) { Properties props = get(); return (props != null) ? props.getProperty(key) : null; @@ -83,9 +56,6 @@ public class AppConfig { FileInputStream fis = null; Properties props = new Properties(); try { - // 读取files目录下的config - // fis = activity.openFileInput(APP_CONFIG); - // 读取app_config目录下的config File dirConf = mContext.getDir(APP_CONFIG, Context.MODE_PRIVATE); fis = new FileInputStream(dirConf.getPath() + File.separator @@ -93,11 +63,9 @@ public class AppConfig { props.load(fis); } catch (Exception e) { + e.printStackTrace(); } finally { - try { - fis.close(); - } catch (Exception e) { - } + StreamUtil.close(fis); } return props; } @@ -105,9 +73,6 @@ public class AppConfig { private void setProps(Properties p) { FileOutputStream fos = null; try { - // 把config建在files目录下 - // fos = activity.openFileOutput(APP_CONFIG, Context.MODE_PRIVATE); - // 把config建在(自定义)app_config的目录下 File dirConf = mContext.getDir(APP_CONFIG, Context.MODE_PRIVATE); File conf = new File(dirConf, APP_CONFIG); @@ -118,19 +83,10 @@ public class AppConfig { } catch (Exception e) { e.printStackTrace(); } finally { - try { - fos.close(); - } catch (Exception e) { - } + StreamUtil.close(fos); } } - public void set(Properties ps) { - Properties props = get(); - props.putAll(ps); - setProps(props); - } - public void set(String key, String value) { Properties props = get(); props.setProperty(key, value); diff --git a/app/src/main/java/net/oschina/app/AppContext.java b/app/src/main/java/net/oschina/app/AppContext.java index f79b7c3a05224195f559f695d519bfd919257611..263877be72cba11bd25aa7f840df6d3bb67f395e 100644 --- a/app/src/main/java/net/oschina/app/AppContext.java +++ b/app/src/main/java/net/oschina/app/AppContext.java @@ -1,108 +1,38 @@ package net.oschina.app; -import android.content.Intent; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager.NameNotFoundException; - -import com.loopj.android.http.AsyncHttpClient; -import com.loopj.android.http.PersistentCookieStore; - -import net.oschina.app.api.ApiHttpClient; import net.oschina.app.base.BaseApplication; -import net.oschina.app.bean.Constants; -import net.oschina.app.bean.User; import net.oschina.app.cache.DataCleanManager; -import net.oschina.app.util.CyptoUtils; import net.oschina.app.util.MethodsCompat; -import net.oschina.app.util.StringUtils; -import net.oschina.app.util.TLog; -import net.oschina.app.util.UIHelper; import org.kymjs.kjframe.Core; -import org.kymjs.kjframe.http.HttpConfig; -import org.kymjs.kjframe.utils.KJLoger; import java.util.Properties; -import java.util.UUID; -import static net.oschina.app.AppConfig.KEY_FRITST_START; import static net.oschina.app.AppConfig.KEY_LOAD_IMAGE; -import static net.oschina.app.AppConfig.KEY_NIGHT_MODE_SWITCH; -import static net.oschina.app.AppConfig.KEY_TWEET_DRAFT; /** - * 全局应用程序类:用于保存和调用全局应用配置及访问网络数据 - * - * @author 火蚁 (http://my.oschina.net/LittleDY) - * @version 1.0 - * @created 2014-04-22 + * 全局应用程序类 + * 用于保存和调用全局应用配置及访问网络数据 */ public class AppContext extends BaseApplication { - public static final int PAGE_SIZE = 20;// 默认分页大小 - private static AppContext instance; - private int loginUid; - - private boolean login; - @Override public void onCreate() { super.onCreate(); instance = this; - init(); - initLogin(); - -// Thread.setDefaultUncaughtExceptionHandler(AppException -// .getAppExceptionHandler(this)); - UIHelper.sendBroadcastForNotice(this); - } - - private void init() { - // 初始化网络请求 - AsyncHttpClient client = new AsyncHttpClient(); - PersistentCookieStore myCookieStore = new PersistentCookieStore(this); - client.setCookieStore(myCookieStore); - ApiHttpClient.setHttpClient(client); - ApiHttpClient.setCookie(ApiHttpClient.getCookie(this)); - - // Log控制器 - KJLoger.openDebutLog(true); - TLog.DEBUG = BuildConfig.DEBUG; - - // Bitmap缓存地址 - HttpConfig.CACHEPATH = "OSChina/imagecache"; - } - - private void initLogin() { - User user = getLoginUser(); - if (null != user && user.getId() > 0) { - login = true; - loginUid = user.getId(); - } else { - this.cleanLoginInfo(); - } } /** * 获得当前app运行的AppContext * - * @return + * @return AppContext */ public static AppContext getInstance() { return instance; } - public boolean containsProperty(String key) { - Properties props = getProperties(); - return props.containsKey(key); - } - - public void setProperties(Properties ps) { - AppConfig.getAppConfig(this).set(ps); - } - public Properties getProperties() { return AppConfig.getAppConfig(this).get(); } @@ -118,160 +48,13 @@ public class AppContext extends BaseApplication { * @return */ public String getProperty(String key) { - String res = AppConfig.getAppConfig(this).get(key); - return res; + return AppConfig.getAppConfig(this).get(key); } public void removeProperty(String... key) { AppConfig.getAppConfig(this).remove(key); } - /** - * 获取App唯一标识 - * - * @return - */ - public String getAppId() { - String uniqueID = getProperty(AppConfig.CONF_APP_UNIQUEID); - if (StringUtils.isEmpty(uniqueID)) { - uniqueID = UUID.randomUUID().toString(); - setProperty(AppConfig.CONF_APP_UNIQUEID, uniqueID); - } - return uniqueID; - } - - /** - * 获取App安装包信息 - * - * @return - */ - public PackageInfo getPackageInfo() { - PackageInfo info = null; - try { - info = getPackageManager().getPackageInfo(getPackageName(), 0); - } catch (NameNotFoundException e) { - e.printStackTrace(System.err); - } - if (info == null) - info = new PackageInfo(); - return info; - } - - /** - * 保存登录信息 - * - * @param user 用户信息 - */ - @SuppressWarnings("serial") - public void saveUserInfo(final User user) { - this.loginUid = user.getId(); - this.login = true; - setProperties(new Properties() { - { - setProperty("user.uid", String.valueOf(user.getId())); - setProperty("user.name", user.getName()); - setProperty("user.face", user.getPortrait());// 用户头像-文件名 - setProperty("user.account", user.getAccount()); - setProperty("user.pwd", - CyptoUtils.encode("oschinaApp", user.getPwd())); - setProperty("user.location", user.getLocation()); - setProperty("user.followers", - String.valueOf(user.getFollowers())); - setProperty("user.fans", String.valueOf(user.getFans())); - setProperty("user.score", String.valueOf(user.getScore())); - setProperty("user.favoritecount", - String.valueOf(user.getFavoritecount())); - setProperty("user.gender", String.valueOf(user.getGender())); - setProperty("user.isRememberMe", - String.valueOf(user.isRememberMe()));// 是否记住我的信息 - } - }); - } - - /** - * 更新用户信息 - * - * @param user - */ - @SuppressWarnings("serial") - public void updateUserInfo(final User user) { - setProperties(new Properties() { - { - setProperty("user.name", user.getName()); - setProperty("user.face", user.getPortrait());// 用户头像-文件名 - setProperty("user.followers", - String.valueOf(user.getFollowers())); - setProperty("user.fans", String.valueOf(user.getFans())); - setProperty("user.score", String.valueOf(user.getScore())); - setProperty("user.favoritecount", - String.valueOf(user.getFavoritecount())); - setProperty("user.gender", String.valueOf(user.getGender())); - } - }); - } - - /** - * 获得登录用户的信息 - * - * @return - */ - public User getLoginUser() { - User user = new User(); - user.setId(StringUtils.toInt(getProperty("user.uid"), 0)); - user.setName(getProperty("user.name")); - user.setPortrait(getProperty("user.face")); - user.setAccount(getProperty("user.account")); - user.setLocation(getProperty("user.location")); - user.setFollowers(StringUtils.toInt(getProperty("user.followers"), 0)); - user.setFans(StringUtils.toInt(getProperty("user.fans"), 0)); - user.setScore(StringUtils.toInt(getProperty("user.score"), 0)); - user.setFavoritecount(StringUtils.toInt( - getProperty("user.favoritecount"), 0)); - user.setRememberMe(StringUtils.toBool(getProperty("user.isRememberMe"))); - user.setGender(getProperty("user.gender")); - return user; - } - - /** - * 清除登录信息 - */ - public void cleanLoginInfo() { - this.loginUid = 0; - this.login = false; - removeProperty("user.uid", "user.name", "user.face", "user.location", - "user.followers", "user.fans", "user.score", - "user.isRememberMe", "user.gender", "user.favoritecount"); - } - - public int getLoginUid() { - return loginUid; - } - - public boolean isLogin() { - return login; - } - - /** - * 用户注销 - */ - public void Logout() { - cleanLoginInfo(); - ApiHttpClient.cleanCookie(); - this.cleanCookie(); - this.login = false; - this.loginUid = 0; - - Intent intent = new Intent(Constants.INTENT_ACTION_LOGOUT); - sendBroadcast(intent); - } - - /** - * 清除保存的缓存 - */ - public void cleanCookie() { - removeProperty(AppConfig.CONF_COOKIE); - } - /** * 清除app缓存 */ @@ -284,6 +67,25 @@ public class AppContext extends BaseApplication { DataCleanManager.cleanCustomCache(MethodsCompat .getExternalCacheDir(this)); } + + /* + Run.onUiSync(new Action() { + @Override + public void call() { + // Glide 清理内存必须在主线程 + Glide.get(OSCApplication.getInstance()).clearMemory(); + } + }); + + AppOperator.runOnThread(new Runnable() { + @Override + public void run() { + // Glide 清理磁盘必须在子线程 + Glide.get(OSCApplication.getInstance()).clearDiskCache(); + } + }); + */ + // 清除编辑器保存的临时内容 Properties props = getProperties(); for (Object key : props.keySet()) { @@ -308,40 +110,4 @@ public class AppContext extends BaseApplication { int currentVersion = android.os.Build.VERSION.SDK_INT; return currentVersion >= VersionCode; } - - public static String getTweetDraft() { - return getPreferences().getString( - KEY_TWEET_DRAFT + getInstance().getLoginUid(), ""); - } - - public static void setTweetDraft(String draft) { - set(KEY_TWEET_DRAFT + getInstance().getLoginUid(), draft); - } - - public static String getNoteDraft() { - return getPreferences().getString( - AppConfig.KEY_NOTE_DRAFT + getInstance().getLoginUid(), ""); - } - - public static void setNoteDraft(String draft) { - set(AppConfig.KEY_NOTE_DRAFT + getInstance().getLoginUid(), draft); - } - - public static boolean isFristStart() { - return getPreferences().getBoolean(KEY_FRITST_START, true); - } - - public static void setFristStart(boolean frist) { - set(KEY_FRITST_START, frist); - } - - //夜间模式 - public static boolean getNightModeSwitch() { - return getPreferences().getBoolean(KEY_NIGHT_MODE_SWITCH, false); - } - - // 设置夜间模式 - public static void setNightModeSwitch(boolean on) { - set(KEY_NIGHT_MODE_SWITCH, on); - } -} +} \ No newline at end of file diff --git a/app/src/main/java/net/oschina/app/AppCrashHandler.java b/app/src/main/java/net/oschina/app/AppCrashHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..eb23359cc6402ae4ed2a029f851ace906a343e85 --- /dev/null +++ b/app/src/main/java/net/oschina/app/AppCrashHandler.java @@ -0,0 +1,66 @@ +package net.oschina.app; + +import android.content.Context; +import android.os.Looper; +import android.widget.Toast; + +/** + * Created by JuQiu + * on 2016/9/13. + */ + +public class AppCrashHandler implements Thread.UncaughtExceptionHandler { + public static final String TAG = "CrashHandler"; + + private Thread.UncaughtExceptionHandler mDefaultHandler; + private static AppCrashHandler INSTANCE = new AppCrashHandler(); + private Context mContext; + + private AppCrashHandler() { + } + + public static AppCrashHandler getInstance() { + return INSTANCE; + } + + public void init(Context context) { + mContext = context; + mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); + Thread.setDefaultUncaughtExceptionHandler(this); + } + + @Override + public void uncaughtException(Thread thread, Throwable ex) { + if (!handleException(ex) && mDefaultHandler != null) { + mDefaultHandler.uncaughtException(thread, ex); + } else { + android.os.Process.killProcess(android.os.Process.myPid()); + System.exit(1); + //ex.printStackTrace(); + } + } + + private boolean handleException(Throwable ex) { + if (ex == null) { + return false; + } + ex.printStackTrace(); + + new Thread() { + @Override + public void run() { + Looper.prepare(); + Toast.makeText(mContext, "OSC出现未知异常,即将退出.", Toast.LENGTH_LONG).show(); + Looper.loop(); + } + }.start(); + + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + return true; + } +} diff --git a/app/src/main/java/net/oschina/app/AppException.java b/app/src/main/java/net/oschina/app/AppException.java index e4d9caa700661a6714ecc727a0be04ed5c3d3734..472313c04c56215a72c1fd82977d3d47d608429c 100644 --- a/app/src/main/java/net/oschina/app/AppException.java +++ b/app/src/main/java/net/oschina/app/AppException.java @@ -1,40 +1,21 @@ package net.oschina.app; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; import java.io.IOException; -import java.io.PrintWriter; -import java.lang.Thread.UncaughtExceptionHandler; import java.net.ConnectException; -import java.net.SocketException; import java.net.UnknownHostException; -import net.oschina.app.util.UIHelper; - -import org.kymjs.kjframe.utils.FileUtils; -import org.kymjs.kjframe.utils.SystemTool; - -import android.content.Context; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.os.Build; -import android.os.Looper; -import cz.msebera.android.httpclient.HttpException; - /** * 应用程序异常:用于捕获异常和提示错误信息 - * + * * @author FireAnt(http://my.oschina.net/LittleDY) * @author kymjs (kymjs123@gmali.com) * @created 2014年9月25日 下午5:34:05 - * */ @SuppressWarnings("serial") -public class AppException extends Exception implements UncaughtExceptionHandler { - - /** 定义异常类型 */ +public class AppException extends Exception { + /** + * 定义异常类型 + */ public final static byte TYPE_NETWORK = 0x01; public final static byte TYPE_SOCKET = 0x02; public final static byte TYPE_HTTP_CODE = 0x03; @@ -49,13 +30,6 @@ public class AppException extends Exception implements UncaughtExceptionHandler // 异常的状态码,这里一般是网络请求的状态码 private int code; - /** 系统默认的UncaughtException处理类 */ - private AppContext mContext; - - private AppException(Context context) { - this.mContext = (AppContext) context; - } - private AppException(byte type, int code, Exception excp) { super(excp); this.type = type; @@ -109,125 +83,7 @@ public class AppException extends Exception implements UncaughtExceptionHandler return new AppException(TYPE_JSON, 0, e); } - // 网络请求异常 - public static AppException network(Exception e) { - if (e instanceof UnknownHostException || e instanceof ConnectException) { - return new AppException(TYPE_NETWORK, 0, e); - } else if (e instanceof HttpException) { - return http(e); - } else if (e instanceof SocketException) { - return socket(e); - } - return http(e); - } - public static AppException run(Exception e) { return new AppException(TYPE_RUN, 0, e); } - - /** - * 获取APP异常崩溃处理对象 - * - * @param context - * @return - */ - public static AppException getAppExceptionHandler(Context context) { - return new AppException(context.getApplicationContext()); - } - - @Override - public void uncaughtException(Thread thread, Throwable ex) { - if (!handleException(ex)) { - System.exit(0); - } - } - - /** - * 自定义异常处理:收集错误信息&发送错误报告 - * - * @param ex - * @return true:处理了该异常信息;否则返回false - */ - private boolean handleException(final Throwable ex) { - if (ex == null || mContext == null) { - return false; - } - boolean success = true; - try { - success = saveToSDCard(ex); - } catch (Exception e) { - } finally { - if (!success) { - return false; - } else { - final Context context = AppManager.getAppManager() - .currentActivity(); - // 显示异常信息&发送报告 - new Thread() { - @Override - public void run() { - Looper.prepare(); - // 拿到未捕获的异常, - UIHelper.sendAppCrashReport(context); - Looper.loop(); - } - }.start(); - } - } - return true; - } - - private boolean saveToSDCard(Throwable ex) throws Exception { - boolean append = false; - File file = FileUtils.getSaveFile("OSChina", "OSCLog.log"); - if (System.currentTimeMillis() - file.lastModified() > 5000) { - append = true; - } - PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter( - file, append))); - // 导出发生异常的时间 - pw.println(SystemTool.getDataTime("yyyy-MM-dd-HH-mm-ss")); - // 导出手机信息 - dumpPhoneInfo(pw); - pw.println(); - // 导出异常的调用栈信息 - ex.printStackTrace(pw); - pw.println(); - pw.close(); - return append; - } - - private void dumpPhoneInfo(PrintWriter pw) throws NameNotFoundException { - // 应用的版本名称和版本号 - PackageManager pm = mContext.getPackageManager(); - PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(), - PackageManager.GET_ACTIVITIES); - pw.print("App Version: "); - pw.print(pi.versionName); - pw.print('_'); - pw.println(pi.versionCode); - pw.println(); - - // android版本号 - pw.print("OS Version: "); - pw.print(Build.VERSION.RELEASE); - pw.print("_"); - pw.println(Build.VERSION.SDK_INT); - pw.println(); - - // 手机制造商 - pw.print("Vendor: "); - pw.println(Build.MANUFACTURER); - pw.println(); - - // 手机型号 - pw.print("Model: "); - pw.println(Build.MODEL); - pw.println(); - - // cpu架构 - pw.print("CPU ABI: "); - pw.println(Build.CPU_ABI); - pw.println(); - } } diff --git a/app/src/main/java/net/oschina/app/AppManager.java b/app/src/main/java/net/oschina/app/AppManager.java deleted file mode 100644 index fde4ac328af0ca1c69b8ccf12811e0e4c8a1ddba..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/AppManager.java +++ /dev/null @@ -1,127 +0,0 @@ -package net.oschina.app; - -import java.util.Stack; - -import android.app.Activity; -import android.content.Context; - -/** - * activity堆栈式管理 - * - * @author FireAnt(http://my.oschina.net/LittleDY) - * @created 2014年10月30日 下午6:22:05 - * - */ -public class AppManager { - - private static Stack activityStack; - private static AppManager instance; - - private AppManager() {} - - /** - * 单一实例 - */ - public static AppManager getAppManager() { - if (instance == null) { - instance = new AppManager(); - } - return instance; - } - - /** - * 添加Activity到堆栈 - */ - public void addActivity(Activity activity) { - if (activityStack == null) { - activityStack = new Stack(); - } - activityStack.add(activity); - } - - /** - * 获取当前Activity(堆栈中最后一个压入的) - */ - public Activity currentActivity() { - Activity activity = activityStack.lastElement(); - return activity; - } - - /** - * 结束当前Activity(堆栈中最后一个压入的) - */ - public void finishActivity() { - Activity activity = activityStack.lastElement(); - finishActivity(activity); - } - - /** - * 结束指定的Activity - */ - public void finishActivity(Activity activity) { - if (activity != null && !activity.isFinishing()) { - activityStack.remove(activity); - activity.finish(); - activity = null; - } - } - - /** - * 结束指定类名的Activity - */ - public void finishActivity(Class cls) { - for (Activity activity : activityStack) { - if (activity.getClass().equals(cls)) { - finishActivity(activity); - break; - } - } - } - - /** - * 结束所有Activity - */ - public void finishAllActivity() { - for (int i = 0, size = activityStack.size(); i < size; i++) { - if (null != activityStack.get(i)) { - //finishActivity方法中的activity.isFinishing()方法会导致某些activity无法销毁 - //貌似跳转的时候最后一个activity 是finishing状态,所以没有执行 - //内部实现不是很清楚,但是实测结果如此,使用下面代码则没有问题 - // find by TopJohn - //finishActivity(activityStack.get(i)); - - activityStack.get(i).finish(); - //break; - } - } - activityStack.clear(); - } - - /** - * 获取指定的Activity - * - * @author kymjs - */ - public static Activity getActivity(Class cls) { - if (activityStack != null) - for (Activity activity : activityStack) { - if (activity.getClass().equals(cls)) { - return activity; - } - } - return null; - } - - /** - * 退出应用程序 - */ - public void AppExit(Context context) { - try { - finishAllActivity(); - // 杀死该应用进程 - android.os.Process.killProcess(android.os.Process.myPid()); - System.exit(0); - } catch (Exception e) { - } - } -} diff --git a/app/src/main/java/net/oschina/app/AppStart.java b/app/src/main/java/net/oschina/app/AppStart.java deleted file mode 100644 index 03161d07331d60e1a43f6584e54f655181e07aed..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/AppStart.java +++ /dev/null @@ -1,94 +0,0 @@ -package net.oschina.app; - -import java.io.File; - -import net.oschina.app.ui.MainActivity; -import net.oschina.app.util.TDevice; - -import org.kymjs.kjframe.http.KJAsyncTask; -import org.kymjs.kjframe.utils.FileUtils; -import org.kymjs.kjframe.utils.PreferenceHelper; - -import android.app.Activity; -import android.content.Intent; -import android.os.Bundle; -import android.view.View; -import android.view.animation.AlphaAnimation; -import android.view.animation.Animation; -import android.view.animation.Animation.AnimationListener; - -/** - * 应用启动界面 - * - * @author FireAnt(http://my.oschina.net/LittleDY) - * @created 2014年12月22日 上午11:51:56 - * - */ -public class AppStart extends Activity { - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - // 防止第三方跳转时出现双实例 - Activity aty = AppManager.getActivity(MainActivity.class); - if (aty != null && !aty.isFinishing()) { - finish(); - } - // SystemTool.gc(this); //针对性能好的手机使用,加快应用相应速度 - - final View view = View.inflate(this, R.layout.app_start, null); - setContentView(view); - // 渐变展示启动屏 - AlphaAnimation aa = new AlphaAnimation(0.5f, 1.0f); - aa.setDuration(800); - view.startAnimation(aa); - aa.setAnimationListener(new AnimationListener() { - @Override - public void onAnimationEnd(Animation arg0) { - redirectTo(); - } - - @Override - public void onAnimationRepeat(Animation animation) {} - - @Override - public void onAnimationStart(Animation animation) {} - }); - } - - @Override - protected void onResume() { - super.onResume(); - int cacheVersion = PreferenceHelper.readInt(this, "first_install", - "first_install", -1); - int currentVersion = TDevice.getVersionCode(); - if (cacheVersion < currentVersion) { - PreferenceHelper.write(this, "first_install", "first_install", - currentVersion); - cleanImageCache(); - } - } - - private void cleanImageCache() { - final File folder = FileUtils.getSaveFolder("OSChina/imagecache"); - KJAsyncTask.execute(new Runnable() { - @Override - public void run() { - for (File file : folder.listFiles()) { - file.delete(); - } - } - }); - } - - /** - * 跳转到... - */ - private void redirectTo() { - Intent uploadLog = new Intent(this, LogUploadService.class); - startService(uploadLog); - Intent intent = new Intent(this, MainActivity.class); - startActivity(intent); - finish(); - } -} diff --git a/app/src/main/java/net/oschina/app/LaunchActivity.java b/app/src/main/java/net/oschina/app/LaunchActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..14162b91149e8ab82c2dd687def98546f49700de --- /dev/null +++ b/app/src/main/java/net/oschina/app/LaunchActivity.java @@ -0,0 +1,70 @@ +package net.oschina.app; + +import android.content.Intent; +import android.os.SystemClock; +import android.text.TextUtils; + +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.base.activities.BaseActivity; +import net.oschina.app.improve.bean.User; +import net.oschina.app.improve.main.MainActivity; +import net.oschina.app.improve.main.tabs.DynamicTabFragment; + +/** + * 应用启动界面 + */ +public class LaunchActivity extends BaseActivity { + @Override + protected int getContentView() { + return R.layout.app_start; + } + + @Override + protected void initData() { + super.initData(); + // 在这里我们检测是否是新版本安装,如果是则进行老版本数据迁移工作 + // 该工作可能消耗大量时间所以放在自线程中执行 + AppOperator.runOnThread(new Runnable() { + @Override + public void run() { + doMerge(); + } + }); + } + + private void doMerge() { + long startTime = System.currentTimeMillis(); + long endTime = 0; + // 判断是否是新版本 + if (Setting.checkIsNewVersion(this)) { + // Cookie迁移 + String cookie = OSCApplication.getInstance().getProperty("cookie"); + if (!TextUtils.isEmpty(cookie)) { + OSCApplication.getInstance().removeProperty("cookie"); + User user = AccountHelper.getUser(); + user.setCookie(cookie); + AccountHelper.updateUserCache(user); + OSCApplication.reInit(); + endTime = System.currentTimeMillis(); + } + } + + // 栏目相关数据合并操作 + DynamicTabFragment.initTabPickerManager(); + // fixme liuhea + long diffTime = endTime - startTime; + SystemClock.sleep(endTime > startTime ? + ((diffTime) > 800 ? 0 : (800 - (diffTime))) + : 800); + + // 完成后进行跳转操作 + redirectTo(); + } + + private void redirectTo() { + Intent intent = new Intent(this, MainActivity.class); + startActivity(intent); + finish(); + } +} diff --git a/app/src/main/java/net/oschina/app/LogUploadService.java b/app/src/main/java/net/oschina/app/LogUploadService.java deleted file mode 100644 index b0dd7ef6c5aa355e7b28e819118da0fd6f5f732f..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/LogUploadService.java +++ /dev/null @@ -1,55 +0,0 @@ -package net.oschina.app; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; - -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.util.StringUtils; - -import cz.msebera.android.httpclient.Header; -import org.kymjs.kjframe.utils.FileUtils; - -import android.app.Service; -import android.content.Intent; -import android.os.IBinder; - -import com.loopj.android.http.AsyncHttpResponseHandler; - -public class LogUploadService extends Service { - - @Override - public IBinder onBind(Intent intent) { - return null; - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - final File log = FileUtils.getSaveFile("OSChina", "OSCLog.log"); - String data = null; - try { - FileInputStream inputStream = new FileInputStream(log); - data = StringUtils.toConvertString(inputStream); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } - if (!StringUtils.isEmpty(data)) { - OSChinaApi.uploadLog(data, new AsyncHttpResponseHandler() { - @Override - public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { - log.delete(); - LogUploadService.this.stopSelf(); - } - - @Override - public void onFailure(int arg0, Header[] arg1, byte[] arg2, - Throwable arg3) { - LogUploadService.this.stopSelf(); - } - }); - } else { - LogUploadService.this.stopSelf(); - } - return super.onStartCommand(intent, flags, startId); - } -} diff --git a/app/src/main/java/net/oschina/app/OSCApplication.java b/app/src/main/java/net/oschina/app/OSCApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..262138b2a84d7005ddcdc8b1d7fc62c2a1f1a654 --- /dev/null +++ b/app/src/main/java/net/oschina/app/OSCApplication.java @@ -0,0 +1,96 @@ +package net.oschina.app; + +import net.oschina.app.api.ApiHttpClient; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.common.helper.ReadStateHelper; + +/** + * Created by qiujuer + * on 2016/10/27. + */ +public class OSCApplication extends AppContext { + private static final String CONFIG_READ_STATE_PRE = "CONFIG_READ_STATE_PRE_"; + + @Override + public void onCreate() { + super.onCreate(); + // 初始化操作 + init(); + } + + public static void reInit() { + ((OSCApplication) OSCApplication.getInstance()).init(); + } + + private void init() { + // 初始化账户基础信息 + AccountHelper.init(this); + // 初始化网络请求 + ApiHttpClient.init(this); + // 初始化异常捕获类 + AppCrashHandler handler = AppCrashHandler.getInstance(); + if (!BuildConfig.DEBUG) + handler.init(this); + } + + /** + * 获取已读状态管理器 + * + * @param mark 传入标示,如:博客:blog; 新闻:news + * @return 已读状态管理器 + */ + public static ReadState getReadState(String mark) { + ReadStateHelper helper = ReadStateHelper.create(getInstance(), + CONFIG_READ_STATE_PRE + mark, 100); + return new ReadState(helper); + } + + /** + * 一个已读状态管理器 + */ + public static class ReadState { + private ReadStateHelper helper; + + ReadState(ReadStateHelper helper) { + this.helper = helper; + } + + /** + * 添加已读状态 + * + * @param key 一般为资讯等Id + */ + public void put(long key) { + helper.put(key); + } + + /** + * 添加已读状态 + * + * @param key 一般为资讯等Id + */ + public void put(String key) { + helper.put(key); + } + + /** + * 获取是否为已读 + * + * @param key 一般为资讯等Id + * @return True 已读 + */ + public boolean already(long key) { + return helper.already(key); + } + + /** + * 获取是否为已读 + * + * @param key 一般为资讯等Id + * @return True 已读 + */ + public boolean already(String key) { + return helper.already(key); + } + } +} diff --git a/app/src/main/java/net/oschina/app/Setting.java b/app/src/main/java/net/oschina/app/Setting.java new file mode 100644 index 0000000000000000000000000000000000000000..82fd574e70465f73113e4f280cf623c7c45742f7 --- /dev/null +++ b/app/src/main/java/net/oschina/app/Setting.java @@ -0,0 +1,35 @@ +package net.oschina.app; + +import android.content.Context; +import android.content.SharedPreferences; +import android.support.v4.content.SharedPreferencesCompat; + +import net.oschina.app.util.TDevice; + +/** + * @author qiujuer Email:qiujuer@live.cn + * @version 1.0.0 + */ +public final class Setting { + public static boolean checkIsNewVersion(Context context) { + int saveVersionCode = getSaveVersionCode(context); + int currentVersionCode = TDevice.getVersionCode(); + if (saveVersionCode < currentVersionCode) { + updateSaveVersionCode(context, currentVersionCode); + return true; + } + return false; + } + + public static int getSaveVersionCode(Context context) { + SharedPreferences sp = context.getSharedPreferences(Setting.class.getName(), Context.MODE_PRIVATE); + return sp.getInt("versionCode", 0); + } + + private static int updateSaveVersionCode(Context context, int version) { + SharedPreferences sp = context.getSharedPreferences(Setting.class.getName(), Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sp.edit().putInt("versionCode", version); + SharedPreferencesCompat.EditorCompat.getInstance().apply(editor); + return version; + } +} diff --git a/app/src/main/java/net/oschina/app/adapter/ActiveAdapter.java b/app/src/main/java/net/oschina/app/adapter/ActiveAdapter.java deleted file mode 100644 index 8b0b3400a970e9a0e024d58c164fe1d4febbcbaf..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/adapter/ActiveAdapter.java +++ /dev/null @@ -1,222 +0,0 @@ -package net.oschina.app.adapter; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.text.Html; -import android.text.Spannable; -import android.text.SpannableString; -import android.text.Spanned; -import android.text.TextUtils; -import android.text.style.ImageSpan; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; - -import net.oschina.app.R; -import net.oschina.app.base.ListBaseAdapter; -import net.oschina.app.bean.Active; -import net.oschina.app.bean.Active.ObjectReply; -import net.oschina.app.emoji.InputHelper; -import net.oschina.app.ui.ImagePreviewActivity; -import net.oschina.app.util.BitmapHelper; -import net.oschina.app.util.ImageUtils; -import net.oschina.app.util.PlatfromUtil; -import net.oschina.app.util.StringUtils; -import net.oschina.app.util.UIHelper; -import net.oschina.app.widget.AvatarView; -import net.oschina.app.widget.MyLinkMovementMethod; -import net.oschina.app.widget.MyURLSpan; -import net.oschina.app.widget.TweetTextView; - -import org.kymjs.kjframe.Core; -import org.kymjs.kjframe.bitmap.BitmapCallBack; -import org.kymjs.kjframe.utils.DensityUtils; - -import butterknife.ButterKnife; -import butterknife.InjectView; - -public class ActiveAdapter extends ListBaseAdapter { - private final static String AT_HOST_PRE = "http://my.oschina.net"; - private final static String MAIN_HOST = "http://www.oschina.net"; - - public ActiveAdapter() { - } - - private Bitmap recordBitmap; - private int rectSize; - - private void initRecordImg(Context cxt) { - recordBitmap = BitmapFactory.decodeResource(cxt.getResources(), - R.drawable.audio3); - recordBitmap = ImageUtils.zoomBitmap(recordBitmap, - DensityUtils.dip2px(cxt, 20f), DensityUtils.dip2px(cxt, 20f)); - } - - private void initImageSize(Context cxt) { - if (cxt != null && rectSize == 0) { - rectSize = (int) cxt.getResources().getDimension(R.dimen.space_100); - } else { - rectSize = 300; - } - } - - @Override - @SuppressLint("InflateParams") - protected View getRealView(int position, View convertView, - final ViewGroup parent) { - ViewHolder vh; - initImageSize(parent.getContext()); - if (convertView == null || convertView.getTag() == null) { - convertView = getLayoutInflater(parent.getContext()).inflate( - R.layout.list_cell_active, null); - vh = new ViewHolder(convertView); - convertView.setTag(vh); - } else { - vh = (ViewHolder) convertView.getTag(); - } - - final Active item = (Active) mDatas.get(position); - - vh.name.setText(item.getAuthor()); - - vh.action.setText(UIHelper.parseActiveAction(item.getObjectType(), - item.getObjectCatalog(), item.getObjectTitle())); - - if (TextUtils.isEmpty(item.getMessage())) { - vh.body.setVisibility(View.GONE); - } else { - vh.body.setMovementMethod(MyLinkMovementMethod.a()); - vh.body.setFocusable(false); - vh.body.setDispatchToParent(true); - vh.body.setLongClickable(false); - - Spanned span = Html.fromHtml(modifyPath(item.getMessage())); - - if (!StringUtils.isEmpty(item.getTweetattach())) { - if (recordBitmap == null) { - initRecordImg(parent.getContext()); - } - ImageSpan recordImg = new ImageSpan(parent.getContext(), - recordBitmap); - SpannableString str = new SpannableString("c"); - str.setSpan(recordImg, 0, 1, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); - vh.body.setText(str); - span = InputHelper.displayEmoji(parent.getContext() - .getResources(), span); - vh.body.append(span); - } else { - span = InputHelper.displayEmoji(parent.getContext() - .getResources(), span); - vh.body.setText(span); - } - MyURLSpan.parseLinkText(vh.body, span); - } - - ObjectReply reply = item.getObjectReply(); - if (reply != null) { - vh.reply.setMovementMethod(MyLinkMovementMethod.a()); - vh.reply.setFocusable(false); - vh.reply.setDispatchToParent(true); - vh.reply.setLongClickable(false); - Spanned span = UIHelper.parseActiveReply(reply.objectName, - reply.objectBody); - vh.reply.setText(span);// - MyURLSpan.parseLinkText(vh.reply, span); - vh.lyReply.setVisibility(TextView.VISIBLE); - } else { - vh.reply.setText(""); - vh.lyReply.setVisibility(TextView.GONE); - } - - vh.time.setText(StringUtils.friendly_time(item.getPubDate())); - - PlatfromUtil.setPlatFromString(vh.from, item.getAppClient()); - - vh.commentCount.setText(item.getCommentCount() + ""); - - vh.avatar.setUserInfo(item.getAuthorId(), item.getAuthor()); - vh.avatar.setAvatarUrl(item.getPortrait()); - - if (!TextUtils.isEmpty(item.getTweetimage())) { - setTweetImage(parent, vh, item); - } else { - vh.pic.setVisibility(View.GONE); - vh.pic.setImageBitmap(null); - } - - return convertView; - } - - /** - * 动态设置图片显示样式 - */ - private void setTweetImage(final ViewGroup parent, final ViewHolder vh, - final Active item) { - vh.pic.setVisibility(View.VISIBLE); - - new Core.Builder().url(item.getTweetimage()).view(vh.pic).loadBitmapRes(R.drawable - .pic_bg).size(rectSize, rectSize).bitmapCallBack(new BitmapCallBack() { - @Override - public void onSuccess(Bitmap bitmap) { - super.onSuccess(bitmap); - if (bitmap != null) { - bitmap = BitmapHelper.scaleWithXY(bitmap, rectSize / bitmap.getHeight()); - vh.pic.setImageBitmap(bitmap); - } - } - }).doTask(); - - vh.pic.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - ImagePreviewActivity.showImagePrivew(parent.getContext(), 0, - new String[]{getOriginalUrl(item.getTweetimage())}); - } - }); - } - - private String modifyPath(String message) { - message = message.replaceAll("(]+href=\")/([\\S]+)\"", "$1" - + AT_HOST_PRE + "/$2\""); - message = message.replaceAll( - "(]+href=\")http://m.oschina.net([\\S]+)\"", "$1" - + MAIN_HOST + "$2\""); - return message; - } - - private String getOriginalUrl(String url) { - return url.replaceAll("_thumb", ""); - } - - static class ViewHolder { - @InjectView(R.id.tv_name) - TextView name; - @InjectView(R.id.tv_from) - TextView from; - @InjectView(R.id.tv_time) - TextView time; - @InjectView(R.id.tv_action) - TextView action; - @InjectView(R.id.tv_action_name) - TextView actionName; - @InjectView(R.id.tv_comment_count) - TextView commentCount; - @InjectView(R.id.tv_body) - TweetTextView body; - @InjectView(R.id.tv_reply) - TweetTextView reply; - @InjectView(R.id.iv_pic) - ImageView pic; - @InjectView(R.id.ly_reply) - View lyReply; - @InjectView(R.id.iv_avatar) - AvatarView avatar; - - public ViewHolder(View view) { - ButterKnife.inject(this, view); - } - } -} diff --git a/app/src/main/java/net/oschina/app/adapter/BlogAdapter.java b/app/src/main/java/net/oschina/app/adapter/BlogAdapter.java index 41d6734ba65fc0b33ce3aa20f0c124be14a8ec60..77892dadd16b5cb1e842b379e7a7c82a167eef5c 100644 --- a/app/src/main/java/net/oschina/app/adapter/BlogAdapter.java +++ b/app/src/main/java/net/oschina/app/adapter/BlogAdapter.java @@ -14,7 +14,7 @@ import net.oschina.app.util.StringUtils; import net.oschina.app.util.ThemeSwitchUtils; import butterknife.ButterKnife; -import butterknife.InjectView; +import butterknife.Bind; /** * @author HuangWenwei @@ -25,21 +25,21 @@ public class BlogAdapter extends ListBaseAdapter { static class ViewHolder { - @InjectView(R.id.tv_title) + @Bind(R.id.tv_title) TextView title; - @InjectView(R.id.tv_description) + @Bind(R.id.tv_description) TextView description; - @InjectView(R.id.tv_source) + @Bind(R.id.tv_source) TextView source; - @InjectView(R.id.tv_time) + @Bind(R.id.tv_time) TextView time; - @InjectView(R.id.tv_comment_count) + @Bind(R.id.tv_comment_count) TextView comment_count; - @InjectView(R.id.iv_tip) + @Bind(R.id.iv_tip) ImageView tip; public ViewHolder(View view) { - ButterKnife.inject(this, view); + ButterKnife.bind(this, view); } } @@ -59,15 +59,14 @@ public class BlogAdapter extends ListBaseAdapter { vh.tip.setVisibility(View.VISIBLE); if (blog.getDocumenttype() == Blog.DOC_TYPE_ORIGINAL) { - vh.tip.setImageResource(R.drawable.widget_original_icon); + vh.tip.setImageResource(R.mipmap.widget_original_icon); } else { - vh.tip.setImageResource(R.drawable.widget_repaste_icon); + vh.tip.setImageResource(R.mipmap.widget_repaste_icon); } vh.title.setText(blog.getTitle()); - if (AppContext.isOnReadedPostList(BlogList.PREF_READED_BLOG_LIST, - blog.getId() + "")) { + if (false) { vh.title.setTextColor(parent.getContext().getResources() .getColor(ThemeSwitchUtils.getTitleReadedColor())); } else { @@ -83,7 +82,7 @@ public class BlogAdapter extends ListBaseAdapter { } vh.source.setText(blog.getAuthor()); - vh.time.setText(StringUtils.friendly_time(blog.getPubDate())); + vh.time.setText(StringUtils.formatSomeAgo(blog.getPubDate())); vh.comment_count.setText(blog.getCommentCount() + ""); return convertView; } diff --git a/app/src/main/java/net/oschina/app/adapter/CommentAdapter.java b/app/src/main/java/net/oschina/app/adapter/CommentAdapter.java deleted file mode 100644 index 4fda914f919a72bd9c5d9d058ae7bf24c74dfe75..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/adapter/CommentAdapter.java +++ /dev/null @@ -1,160 +0,0 @@ -package net.oschina.app.adapter; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.text.Html; -import android.text.Spanned; -import android.view.View; -import android.view.ViewGroup; -import android.widget.LinearLayout; -import android.widget.TextView; - -import net.oschina.app.R; -import net.oschina.app.base.ListBaseAdapter; -import net.oschina.app.bean.Comment; -import net.oschina.app.bean.Comment.Refer; -import net.oschina.app.bean.Comment.Reply; -import net.oschina.app.emoji.InputHelper; -import net.oschina.app.util.PlatfromUtil; -import net.oschina.app.util.StringUtils; -import net.oschina.app.widget.AvatarView; -import net.oschina.app.widget.FloorView; -import net.oschina.app.widget.MyLinkMovementMethod; -import net.oschina.app.widget.MyURLSpan; -import net.oschina.app.widget.TweetTextView; - -import java.util.List; - -import butterknife.ButterKnife; -import butterknife.InjectView; - -public class CommentAdapter extends ListBaseAdapter { - - @SuppressLint({ "InflateParams", "CutPasteId" }) - @Override - protected View getRealView(int position, View convertView, - final ViewGroup parent) { - ViewHolder vh = null; - if (convertView == null || convertView.getTag() == null) { - convertView = getLayoutInflater(parent.getContext()).inflate( - R.layout.list_cell_comment, null); - vh = new ViewHolder(convertView); - convertView.setTag(vh); - } else { - vh = (ViewHolder) convertView.getTag(); - } - try { - - final Comment item = mDatas.get(position); - - // 若Authorid为0,则显示非会员 - vh.name.setText(item.getAuthor() - + (item.getAuthorId() == 0 ? "(非会员)" : "")); - - vh.content.setMovementMethod(MyLinkMovementMethod.a()); - vh.content.setFocusable(false); - vh.content.setDispatchToParent(true); - vh.content.setLongClickable(false); - Spanned span = Html.fromHtml(TweetTextView.modifyPath(item - .getContent())); - span = InputHelper.displayEmoji(parent.getContext().getResources(), - span.toString()); - vh.content.setText(span); - MyURLSpan.parseLinkText(vh.content, span); - - vh.time.setText(StringUtils.friendly_time(item.getPubDate())); - - PlatfromUtil.setPlatFromString(vh.from, item.getAppClient()); - - // setup refers - setupRefers(parent.getContext(), vh, item.getRefers()); - - // setup replies - setupReplies(parent.getContext(), vh, item.getReplies()); - - vh.avatar.setAvatarUrl(item.getPortrait()); - vh.avatar.setUserInfo(item.getAuthorId(), item.getAuthor()); - } catch (Exception e) { - } - return convertView; - } - - private void setupRefers(Context context, ViewHolder vh, List refers) { - vh.refers.removeAllViews(); - if (refers == null || refers.size() <= 0) { - vh.refers.setVisibility(View.GONE); - } else { - vh.refers.setVisibility(View.VISIBLE); - - vh.refers.setComments(refers); - } - } - - private void setupReplies(Context context, ViewHolder vh, - List replies) { - vh.relies.removeAllViews(); - if (replies == null || replies.size() <= 0) { - vh.relies.setVisibility(View.GONE); - } else { - vh.relies.setVisibility(View.VISIBLE); - - // add count layout - View countView = getLayoutInflater(context).inflate( - R.layout.list_cell_reply_count, null, false); - TextView count = (TextView) countView - .findViewById(R.id.tv_comment_reply_count); - count.setText(context.getResources().getString( - R.string.comment_reply_count, replies.size())); - vh.relies.addView(countView); - - // add reply item - for (Reply reply : replies) { - LinearLayout replyItemView = (LinearLayout) getLayoutInflater( - context).inflate(R.layout.list_cell_reply_name_content, - null, false); - - replyItemView.setOrientation(LinearLayout.HORIZONTAL); - - replyItemView - .setBackgroundResource(R.drawable.comment_background); - - TextView name = (TextView) replyItemView - .findViewById(R.id.tv_reply_name); - name.setText(reply.rauthor + ":"); - - TweetTextView replyContent = (TweetTextView) replyItemView - .findViewById(R.id.tv_reply_content); - replyContent.setMovementMethod(MyLinkMovementMethod.a()); - replyContent.setFocusable(false); - replyContent.setDispatchToParent(true); - replyContent.setLongClickable(false); - Spanned rcontent = Html.fromHtml(reply.rcontent); - replyContent.setText(rcontent); - MyURLSpan.parseLinkText(replyContent, rcontent); - - vh.relies.addView(replyItemView); - } - } - } - - static class ViewHolder { - @InjectView(R.id.iv_avatar) - AvatarView avatar; - @InjectView(R.id.tv_name) - TextView name; - @InjectView(R.id.tv_time) - TextView time; - @InjectView(R.id.tv_from) - TextView from; - @InjectView(R.id.tv_content) - TweetTextView content; - @InjectView(R.id.ly_relies) - LinearLayout relies; - @InjectView(R.id.ly_refers) - FloorView refers; - - ViewHolder(View view) { - ButterKnife.inject(this, view); - } - } -} diff --git a/app/src/main/java/net/oschina/app/adapter/EventAdapter.java b/app/src/main/java/net/oschina/app/adapter/EventAdapter.java index eb42ca3a4a7a03e0edbba812f6981ea9772bf8bb..5183fd72b574a1544b6be84c97ce2d8cad60f0fa 100644 --- a/app/src/main/java/net/oschina/app/adapter/EventAdapter.java +++ b/app/src/main/java/net/oschina/app/adapter/EventAdapter.java @@ -13,7 +13,7 @@ import net.oschina.app.bean.EventList; import org.kymjs.kjframe.Core; import butterknife.ButterKnife; -import butterknife.InjectView; +import butterknife.Bind; /** * 活动列表适配器 @@ -27,19 +27,19 @@ public class EventAdapter extends ListBaseAdapter { static class ViewHolder { - @InjectView(R.id.iv_event_status) + @Bind(R.id.iv_event_status) ImageView status; - @InjectView(R.id.iv_event_img) + @Bind(R.id.iv_event_img) ImageView img; - @InjectView(R.id.tv_event_title) + @Bind(R.id.tv_event_title) TextView title; - @InjectView(R.id.tv_event_time) + @Bind(R.id.tv_event_time) TextView time; - @InjectView(R.id.tv_event_spot) + @Bind(R.id.tv_event_spot) TextView spot; public ViewHolder(View view) { - ButterKnife.inject(this, view); + ButterKnife.bind(this, view); } } @@ -52,7 +52,7 @@ public class EventAdapter extends ListBaseAdapter { ViewHolder vh = null; if (convertView == null || convertView.getTag() == null) { convertView = getLayoutInflater(parent.getContext()).inflate( - R.layout.list_cell_event, null); + R.layout.list_cell_event, parent, false); vh = new ViewHolder(convertView); convertView.setTag(vh); } else { @@ -77,8 +77,7 @@ public class EventAdapter extends ListBaseAdapter { case EventList.EVENT_LIST_TYPE_NEW_EVENT: if (event.getApplyStatus() == Event.APPLYSTATUS_CHECKING || event.getApplyStatus() == Event.APPLYSTATUS_CHECKED) { - vh.status - .setImageResource(R.drawable.icon_event_status_checked); + vh.status.setImageResource(R.mipmap.icon_event_status_checked); vh.status.setVisibility(View.VISIBLE); } else { vh.status.setVisibility(View.GONE); @@ -86,12 +85,11 @@ public class EventAdapter extends ListBaseAdapter { break; case EventList.EVENT_LIST_TYPE_MY_EVENT: if (event.getApplyStatus() == Event.APPLYSTATUS_ATTEND) { - vh.status.setImageResource(R.drawable.icon_event_status_attend); + vh.status.setImageResource(R.mipmap.icon_event_status_attend); } else if (event.getStatus() == Event.EVNET_STATUS_APPLYING) { - vh.status - .setImageResource(R.drawable.icon_event_status_checked); + vh.status.setImageResource(R.mipmap.icon_event_status_checked); } else { - vh.status.setImageResource(R.drawable.icon_event_status_over); + vh.status.setImageResource(R.mipmap.icon_event_status_over); } vh.status.setVisibility(View.VISIBLE); break; diff --git a/app/src/main/java/net/oschina/app/adapter/EventApplyAdapter.java b/app/src/main/java/net/oschina/app/adapter/EventApplyAdapter.java index 2b8f0b3711991af070e17937e6978043d574b71e..0d953a7b80db1a59f70d7f1015a4330e7740b7de 100644 --- a/app/src/main/java/net/oschina/app/adapter/EventApplyAdapter.java +++ b/app/src/main/java/net/oschina/app/adapter/EventApplyAdapter.java @@ -1,16 +1,18 @@ package net.oschina.app.adapter; -import net.oschina.app.R; -import net.oschina.app.base.ListBaseAdapter; -import net.oschina.app.bean.Apply; -import net.oschina.app.widget.AvatarView; import android.annotation.SuppressLint; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; + +import net.oschina.app.R; +import net.oschina.app.base.ListBaseAdapter; +import net.oschina.app.bean.Apply; +import net.oschina.app.widget.AvatarView; + +import butterknife.Bind; import butterknife.ButterKnife; -import butterknife.InjectView; /** * 活动参会人员适配器 @@ -48,18 +50,18 @@ public class EventApplyAdapter extends ListBaseAdapter { static class ViewHolder { - @InjectView(R.id.tv_name) + @Bind(R.id.tv_name) TextView name; - @InjectView(R.id.tv_desc) + @Bind(R.id.tv_desc) TextView desc; - @InjectView(R.id.tv_from) TextView from; - @InjectView(R.id.iv_gender) + @Bind(R.id.tv_from) TextView from; + @Bind(R.id.iv_gender) ImageView gender; - @InjectView(R.id.iv_avatar) + @Bind(R.id.iv_avatar) AvatarView avatar; public ViewHolder(View view) { - ButterKnife.inject(this, view); + ButterKnife.bind(this, view); } } } diff --git a/app/src/main/java/net/oschina/app/adapter/FindUserAdapter.java b/app/src/main/java/net/oschina/app/adapter/FindUserAdapter.java deleted file mode 100644 index c6a538dc894c782f8c4c2d55ca55442ce764eb39..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/adapter/FindUserAdapter.java +++ /dev/null @@ -1,74 +0,0 @@ -package net.oschina.app.adapter; - -import net.oschina.app.R; -import net.oschina.app.base.ListBaseAdapter; -import net.oschina.app.bean.User; -import net.oschina.app.widget.AvatarView; -import android.annotation.SuppressLint; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; -import butterknife.ButterKnife; -import butterknife.InjectView; - -/** - * 好友列表适配器 - * - * @author FireAnt(http://my.oschina.net/LittleDY) - * @created 2014年11月6日 上午11:22:27 - * - */ -public class FindUserAdapter extends ListBaseAdapter { - - @SuppressLint("InflateParams") - @Override - protected View getRealView(int position, View convertView, - final ViewGroup parent) { - ViewHolder vh = null; - if (convertView == null || convertView.getTag() == null) { - convertView = getLayoutInflater(parent.getContext()).inflate( - R.layout.list_cell_friend, null); - vh = new ViewHolder(convertView); - convertView.setTag(vh); - } else { - vh = (ViewHolder) convertView.getTag(); - } - - final User item = (User) mDatas.get(position); - - vh.name.setText(item.getName()); - - vh.from.setText(item.getFrom()); - vh.desc.setVisibility(View.GONE); - int genderIcon = R.drawable.userinfo_icon_male; - if ("女".equals(item.getGender())) { - genderIcon = R.drawable.userinfo_icon_female; - } - - vh.gender.setImageResource(genderIcon); - - vh.avatar.setAvatarUrl(item.getPortrait()); - vh.avatar.setUserInfo(item.getId(), item.getName()); - - return convertView; - } - - static class ViewHolder { - - @InjectView(R.id.tv_name) - TextView name; - @InjectView(R.id.tv_from) - TextView from; - @InjectView(R.id.tv_desc) - TextView desc; - @InjectView(R.id.iv_gender) - ImageView gender; - @InjectView(R.id.iv_avatar) - AvatarView avatar; - - public ViewHolder(View view) { - ButterKnife.inject(this, view); - } - } -} diff --git a/app/src/main/java/net/oschina/app/adapter/FriendAdapter.java b/app/src/main/java/net/oschina/app/adapter/FriendAdapter.java deleted file mode 100644 index 2992593916d34ddfdc16d4f17fb0e5d67b62494e..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/adapter/FriendAdapter.java +++ /dev/null @@ -1,82 +0,0 @@ -package net.oschina.app.adapter; - -import net.oschina.app.R; -import net.oschina.app.base.ListBaseAdapter; -import net.oschina.app.bean.Friend; -import net.oschina.app.util.StringUtils; -import net.oschina.app.widget.AvatarView; -import android.annotation.SuppressLint; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; -import butterknife.ButterKnife; -import butterknife.InjectView; - -/** - * 好友列表适配器 - * - * @author FireAnt(http://my.oschina.net/LittleDY) - * @created 2014年11月6日 上午11:22:27 - * - */ -public class FriendAdapter extends ListBaseAdapter { - - @SuppressLint("InflateParams") - @Override - protected View getRealView(int position, View convertView, - final ViewGroup parent) { - ViewHolder vh = null; - if (convertView == null || convertView.getTag() == null) { - convertView = getLayoutInflater(parent.getContext()).inflate( - R.layout.list_cell_friend, null); - vh = new ViewHolder(convertView); - convertView.setTag(vh); - } else { - vh = (ViewHolder) convertView.getTag(); - } - - final Friend item = mDatas.get(position); - - vh.name.setText(item.getName()); - String from = item.getFrom(); - if (from != null || !StringUtils.isEmpty(from)) { - vh.from.setText(from); - } else { - vh.from.setVisibility(View.GONE); - } - String desc = item.getExpertise(); - if (desc != null || !StringUtils.isEmpty(from) || !"<无>".equals(desc)) { - vh.desc.setText(item.getExpertise()); - } else { - vh.desc.setVisibility(View.GONE); - } - - vh.gender - .setImageResource(item.getGender() == 1 ? R.drawable.userinfo_icon_male - : R.drawable.userinfo_icon_female); - - vh.avatar.setAvatarUrl(item.getPortrait()); - vh.avatar.setUserInfo(item.getUserid(), item.getName()); - - return convertView; - } - - static class ViewHolder { - - @InjectView(R.id.tv_name) - TextView name; - @InjectView(R.id.tv_from) - TextView from; - @InjectView(R.id.tv_desc) - TextView desc; - @InjectView(R.id.iv_gender) - ImageView gender; - @InjectView(R.id.iv_avatar) - AvatarView avatar; - - public ViewHolder(View view) { - ButterKnife.inject(this, view); - } - } -} diff --git a/app/src/main/java/net/oschina/app/adapter/MessageAdapter.java b/app/src/main/java/net/oschina/app/adapter/MessageAdapter.java index 4a0c74d2f21792d6bbe484f5f84a2a81465e29a5..5963b8a85f973efd957305b6af70b002b3365016 100644 --- a/app/src/main/java/net/oschina/app/adapter/MessageAdapter.java +++ b/app/src/main/java/net/oschina/app/adapter/MessageAdapter.java @@ -1,21 +1,23 @@ package net.oschina.app.adapter; -import net.oschina.app.AppContext; +import android.text.Html; +import android.text.Spanned; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + import net.oschina.app.R; import net.oschina.app.base.ListBaseAdapter; import net.oschina.app.bean.Messages; +import net.oschina.app.improve.account.AccountHelper; import net.oschina.app.util.StringUtils; import net.oschina.app.widget.AvatarView; import net.oschina.app.widget.MyLinkMovementMethod; import net.oschina.app.widget.MyURLSpan; import net.oschina.app.widget.TweetTextView; -import android.text.Html; -import android.text.Spanned; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; + +import butterknife.Bind; import butterknife.ButterKnife; -import butterknife.InjectView; public class MessageAdapter extends ListBaseAdapter { @@ -26,7 +28,7 @@ public class MessageAdapter extends ListBaseAdapter { @Override protected View getRealView(int position, View convertView, - final ViewGroup parent) { + final ViewGroup parent) { ViewHolder vh = null; if (convertView == null || convertView.getTag() == null) { convertView = getLayoutInflater(parent.getContext()).inflate( @@ -39,7 +41,7 @@ public class MessageAdapter extends ListBaseAdapter { final Messages item = (Messages) mDatas.get(position); - if (AppContext.getInstance().getLoginUid() == item.getSenderId()) { + if (AccountHelper.getUserId() == item.getSenderId()) { vh.sender.setVisibility(View.VISIBLE); } else { vh.sender.setVisibility(View.GONE); @@ -55,9 +57,8 @@ public class MessageAdapter extends ListBaseAdapter { vh.content.setText(span); MyURLSpan.parseLinkText(vh.content, span); - vh.time.setText(StringUtils.friendly_time(item.getPubDate())); - vh.count.setText(parent.getResources().getString( - R.string.message_count, item.getMessageCount())); + vh.time.setText(StringUtils.formatSomeAgo(item.getPubDate())); + vh.count.setText(parent.getResources().getString(R.string.message_count, item.getMessageCount() + "")); vh.avatar.setAvatarUrl(item.getPortrait()); vh.avatar.setUserInfo(item.getSenderId(), item.getSender()); @@ -65,21 +66,21 @@ public class MessageAdapter extends ListBaseAdapter { } static class ViewHolder { - @InjectView(R.id.iv_avatar) + @Bind(R.id.iv_avatar) AvatarView avatar; - @InjectView(R.id.tv_name) + @Bind(R.id.tv_name) TextView name; - @InjectView(R.id.tv_sender) + @Bind(R.id.tv_sender) TextView sender; - @InjectView(R.id.tv_time) + @Bind(R.id.tv_time) TextView time; - @InjectView(R.id.tv_count) + @Bind(R.id.tv_count) TextView count; - @InjectView(R.id.tv_content) + @Bind(R.id.tv_content) TweetTextView content; ViewHolder(View view) { - ButterKnife.inject(this, view); + ButterKnife.bind(this, view); } } } diff --git a/app/src/main/java/net/oschina/app/adapter/MessageDetailAdapter.java b/app/src/main/java/net/oschina/app/adapter/MessageDetailAdapter.java index f93e83a2758ece46bba2e99af8193566b25895ff..ea83dc34b69673b1b27e968e24d076df096beb8f 100644 --- a/app/src/main/java/net/oschina/app/adapter/MessageDetailAdapter.java +++ b/app/src/main/java/net/oschina/app/adapter/MessageDetailAdapter.java @@ -10,16 +10,15 @@ import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.TextView; -import net.oschina.app.AppContext; import net.oschina.app.R; -import net.oschina.app.api.ApiHttpClient; import net.oschina.app.base.ListBaseAdapter; import net.oschina.app.bean.MessageDetail; import net.oschina.app.emoji.InputHelper; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.ui.OSCPhotosActivity; import net.oschina.app.util.ChatImageDisplayer; import net.oschina.app.util.StringUtils; import net.oschina.app.util.TDevice; -import net.oschina.app.util.UIHelper; import net.oschina.app.widget.AvatarView; import net.oschina.app.widget.MyLinkMovementMethod; import net.oschina.app.widget.MyURLSpan; @@ -28,12 +27,11 @@ import net.oschina.app.widget.TweetTextView; import org.kymjs.kjframe.Core; import org.kymjs.kjframe.KJBitmap; import org.kymjs.kjframe.bitmap.BitmapConfig; -import org.kymjs.kjframe.http.HttpConfig; import java.lang.reflect.Field; +import butterknife.Bind; import butterknife.ButterKnife; -import butterknife.InjectView; import butterknife.OnClick; /** @@ -75,7 +73,7 @@ public class MessageDetailAdapter extends ListBaseAdapter { final MessageDetail item = mDatas.get(mDatas.size() - position - 1); int itemType = 0; - if (item.getAuthorId() == AppContext.getInstance().getLoginUid()) { + if (item.getAuthorId() == AccountHelper.getUserId()) { itemType = 1; } boolean needCreateView = false; @@ -149,9 +147,8 @@ public class MessageDetailAdapter extends ListBaseAdapter { vh.content.setVisibility(View.GONE); vh.image.setVisibility(View.VISIBLE); //加载图片 - vh.image.setImageResource(R.drawable.load_img_loading); - HttpConfig.sCookie = ApiHttpClient.getCookie(AppContext.getInstance()); - mKjBitmap.display(vh.image, msg.getContent(), R.drawable.load_img_error, 0, 0, + vh.image.setImageResource(R.mipmap.load_img_loading); + mKjBitmap.display(vh.image, msg.getContent(), R.mipmap.load_img_error, 3000, 3000, null); } @@ -201,23 +198,23 @@ public class MessageDetailAdapter extends ListBaseAdapter { class ViewHolder { int type; - @InjectView(R.id.iv_avatar) + @Bind(R.id.iv_avatar) AvatarView avatar; - @InjectView(R.id.tv_time) + @Bind(R.id.tv_time) TextView time; - @InjectView(R.id.tv_content) + @Bind(R.id.tv_content) TweetTextView content; - @InjectView(R.id.iv_img) + @Bind(R.id.iv_img) ImageView image; - @InjectView(R.id.progress) + @Bind(R.id.progress) ProgressBar progressBar; - @InjectView(R.id.rl_msg_status_panel) + @Bind(R.id.rl_msg_status_panel) RelativeLayout msgStatusPanel; - @InjectView(R.id.itv_error) + @Bind(R.id.itv_error) IconTextView error; ViewHolder(View view) { - ButterKnife.inject(this, view); + ButterKnife.bind(this, view); content.setMovementMethod(MyLinkMovementMethod.a()); content.setFocusable(false); @@ -229,7 +226,7 @@ public class MessageDetailAdapter extends ListBaseAdapter { void viewImage(View v) { if (v.getTag() != null) { String url = (String) v.getTag(); - UIHelper.showImagePreview(v.getContext(), new String[]{url}); + OSCPhotosActivity.showImagePreview(v.getContext(), url); } } diff --git a/app/src/main/java/net/oschina/app/adapter/NewsAdapter.java b/app/src/main/java/net/oschina/app/adapter/NewsAdapter.java index 19382b7e166493e41a057dbb60252dd98a1a8332..0d7eb69bb3012eed72702ade8d2ec5146d23618c 100644 --- a/app/src/main/java/net/oschina/app/adapter/NewsAdapter.java +++ b/app/src/main/java/net/oschina/app/adapter/NewsAdapter.java @@ -15,7 +15,7 @@ import net.oschina.app.util.StringUtils; import net.oschina.app.util.ThemeSwitchUtils; import butterknife.ButterKnife; -import butterknife.InjectView; +import butterknife.Bind; public class NewsAdapter extends ListBaseAdapter { @@ -35,8 +35,7 @@ public class NewsAdapter extends ListBaseAdapter { News news = mDatas.get(position); vh.title.setText(news.getTitle()); - if (AppContext.isOnReadedPostList(NewsList.PREF_READED_NEWS_LIST, - news.getId() + "")) { + if (false) { vh.title.setTextColor(parent.getContext().getResources() .getColor(ThemeSwitchUtils.getTitleReadedColor())); } else { @@ -57,28 +56,28 @@ public class NewsAdapter extends ListBaseAdapter { } else { vh.tip.setVisibility(View.GONE); } - vh.time.setText(StringUtils.friendly_time(news.getPubDate())); + vh.time.setText(StringUtils.formatSomeAgo(news.getPubDate())); vh.comment_count.setText(news.getCommentCount() + ""); return convertView; } static class ViewHolder { - @InjectView(R.id.tv_title) + @Bind(R.id.tv_title) TextView title; - @InjectView(R.id.tv_description) + @Bind(R.id.tv_description) TextView description; - @InjectView(R.id.tv_source) + @Bind(R.id.tv_source) TextView source; - @InjectView(R.id.tv_time) + @Bind(R.id.tv_time) TextView time; - @InjectView(R.id.tv_comment_count) + @Bind(R.id.tv_comment_count) TextView comment_count; - @InjectView(R.id.iv_tip) + @Bind(R.id.iv_tip) ImageView tip; public ViewHolder(View view) { - ButterKnife.inject(this, view); + ButterKnife.bind(this, view); } } } diff --git a/app/src/main/java/net/oschina/app/adapter/PostAdapter.java b/app/src/main/java/net/oschina/app/adapter/PostAdapter.java index f51d60b36c361e2f52b4353fbba7aece3a8a16ce..fe6ca691a1dd14cd038fc2c595ff20cf472d89a1 100644 --- a/app/src/main/java/net/oschina/app/adapter/PostAdapter.java +++ b/app/src/main/java/net/oschina/app/adapter/PostAdapter.java @@ -15,7 +15,7 @@ import net.oschina.app.util.ThemeSwitchUtils; import net.oschina.app.widget.AvatarView; import butterknife.ButterKnife; -import butterknife.InjectView; +import butterknife.Bind; /** * post(讨论区帖子)适配器 @@ -27,22 +27,22 @@ public class PostAdapter extends ListBaseAdapter { static class ViewHolder { - @InjectView(R.id.tv_title) + @Bind(R.id.tv_title) TextView title; - @InjectView(R.id.tv_description) + @Bind(R.id.tv_description) TextView description; - @InjectView(R.id.tv_author) + @Bind(R.id.tv_author) TextView author; - @InjectView(R.id.tv_date) + @Bind(R.id.tv_date) TextView time; - @InjectView(R.id.tv_count) + @Bind(R.id.tv_count) TextView comment_count; - @InjectView(R.id.iv_face) + @Bind(R.id.iv_face) public AvatarView face; public ViewHolder(View view) { - ButterKnife.inject(this, view); + ButterKnife.bind(this, view); } } @@ -70,8 +70,7 @@ public class PostAdapter extends ListBaseAdapter { vh.description.setText(HTMLUtil.replaceTag(post.getBody()).trim()); } - if (AppContext.isOnReadedPostList(PostList.PREF_READED_POST_LIST, - post.getId() + "")) { + if (false) { vh.title.setTextColor(parent.getContext().getResources() .getColor(ThemeSwitchUtils.getTitleReadedColor())); } else { @@ -80,7 +79,7 @@ public class PostAdapter extends ListBaseAdapter { } vh.author.setText(post.getAuthor()); - vh.time.setText(StringUtils.friendly_time(post.getPubDate())); + vh.time.setText(StringUtils.formatSomeAgo(post.getPubDate())); vh.comment_count.setText(post.getAnswerCount() + "回 / " + post.getViewCount() + "阅"); diff --git a/app/src/main/java/net/oschina/app/adapter/RecycleBin.java b/app/src/main/java/net/oschina/app/adapter/RecycleBin.java deleted file mode 100644 index e46514b864d4bdf989d5d762e4901e6f7e8b7435..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/adapter/RecycleBin.java +++ /dev/null @@ -1,155 +0,0 @@ -package net.oschina.app.adapter; - -import android.annotation.SuppressLint; -import android.os.Build; -import android.util.SparseArray; -import android.view.View; - -/** - * The RecycleBin facilitates reuse of views across layouts. The RecycleBin has two levels of - * storage: ActiveViews and ScrapViews. ActiveViews are those views which were onscreen at the - * start of a layout. By construction, they are displaying current information. At the end of - * layout, all views in ActiveViews are demoted to ScrapViews. ScrapViews are old views that - * could potentially be used by the adapter to avoid allocating views unnecessarily. - *

- * This class was taken from Android's implementation of {@link android.widget.AbsListView} which - * is copyrighted 2006 The Android Open Source Project. - */ -public class RecycleBin { - /** - * Views that were on screen at the start of layout. This array is populated at the start of - * layout, and at the end of layout all view in activeViews are moved to scrapViews. - * Views in activeViews represent a contiguous range of Views, with position of the first - * view store in mFirstActivePosition. - */ - private View[] activeViews = new View[0]; - private int[] activeViewTypes = new int[0]; - - /** Unsorted views that can be used by the adapter as a convert view. */ - private SparseArray[] scrapViews; - - private int viewTypeCount; - - private SparseArray currentScrapViews; - - public void setViewTypeCount(int viewTypeCount) { - if (viewTypeCount < 1) { - throw new IllegalArgumentException("Can't have a viewTypeCount < 1"); - } - //noinspection unchecked - SparseArray[] scrapViews = new SparseArray[viewTypeCount]; - for (int i = 0; i < viewTypeCount; i++) { - scrapViews[i] = new SparseArray(); - } - this.viewTypeCount = viewTypeCount; - currentScrapViews = scrapViews[0]; - this.scrapViews = scrapViews; - } - - protected boolean shouldRecycleViewType(int viewType) { - return viewType >= 0; - } - - /** @return A view from the ScrapViews collection. These are unordered. */ - View getScrapView(int position, int viewType) { - if (viewTypeCount == 1) { - return retrieveFromScrap(currentScrapViews, position); - } else if (viewType >= 0 && viewType < scrapViews.length) { - return retrieveFromScrap(scrapViews[viewType], position); - } - return null; - } - - /** - * Put a view into the ScrapViews list. These views are unordered. - * - * @param scrap The view to add - */ - @SuppressLint("NewApi") -void addScrapView(View scrap, int position, int viewType) { - if (viewTypeCount == 1) { - currentScrapViews.put(position, scrap); - } else { - scrapViews[viewType].put(position, scrap); - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { - scrap.setAccessibilityDelegate(null); - } - } - - /** Move all views remaining in activeViews to scrapViews. */ - @SuppressLint("NewApi") -void scrapActiveViews() { - final View[] activeViews = this.activeViews; - final int[] activeViewTypes = this.activeViewTypes; - final boolean multipleScraps = viewTypeCount > 1; - - SparseArray scrapViews = currentScrapViews; - final int count = activeViews.length; - for (int i = count - 1; i >= 0; i--) { - final View victim = activeViews[i]; - if (victim != null) { - int whichScrap = activeViewTypes[i]; - - activeViews[i] = null; - activeViewTypes[i] = -1; - - if (!shouldRecycleViewType(whichScrap)) { - continue; - } - - if (multipleScraps) { - scrapViews = this.scrapViews[whichScrap]; - } - scrapViews.put(i, victim); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { - victim.setAccessibilityDelegate(null); - } - } - } - - pruneScrapViews(); - } - - /** - * Makes sure that the size of scrapViews does not exceed the size of activeViews. - * (This can happen if an adapter does not recycle its views). - */ - private void pruneScrapViews() { - final int maxViews = activeViews.length; - final int viewTypeCount = this.viewTypeCount; - final SparseArray[] scrapViews = this.scrapViews; - for (int i = 0; i < viewTypeCount; ++i) { - final SparseArray scrapPile = scrapViews[i]; - int size = scrapPile.size(); - final int extras = size - maxViews; - size--; - for (int j = 0; j < extras; j++) { - scrapPile.remove(scrapPile.keyAt(size--)); - } - } - } - - static View retrieveFromScrap(SparseArray scrapViews, int position) { - int size = scrapViews.size(); - if (size > 0) { - // See if we still have a view for this position. - for (int i = 0; i < size; i++) { - int fromPosition = scrapViews.keyAt(i); - View view = scrapViews.get(fromPosition); - if (fromPosition == position) { - scrapViews.remove(fromPosition); - return view; - } - } - int index = size - 1; - View r = scrapViews.valueAt(index); - scrapViews.remove(scrapViews.keyAt(index)); - return r; - } else { - return null; - } - } -} diff --git a/app/src/main/java/net/oschina/app/adapter/RecyclingPagerAdapter.java b/app/src/main/java/net/oschina/app/adapter/RecyclingPagerAdapter.java deleted file mode 100644 index 84e7d8859c0061d5d9fac6f4250a5765765bc807..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/adapter/RecyclingPagerAdapter.java +++ /dev/null @@ -1,122 +0,0 @@ -package net.oschina.app.adapter; - -import android.support.v4.view.PagerAdapter; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; - -/** - * A {@link PagerAdapter} which behaves like an {@link android.widget.Adapter} - * with view types and view recycling. - */ -public abstract class RecyclingPagerAdapter extends PagerAdapter { - static final int IGNORE_ITEM_VIEW_TYPE = AdapterView.ITEM_VIEW_TYPE_IGNORE; - - private final RecycleBin recycleBin; - - public RecyclingPagerAdapter() { - this(new RecycleBin()); - } - - RecyclingPagerAdapter(RecycleBin recycleBin) { - this.recycleBin = recycleBin; - recycleBin.setViewTypeCount(getViewTypeCount()); - } - - @Override - public void notifyDataSetChanged() { - recycleBin.scrapActiveViews(); - super.notifyDataSetChanged(); - } - - @Override - public final Object instantiateItem(ViewGroup container, int position) { - int viewType = getItemViewType(position); - View view = null; - if (viewType != IGNORE_ITEM_VIEW_TYPE) { - view = recycleBin.getScrapView(position, viewType); - } - view = getView(position, view, container); - container.addView(view); - return view; - } - - @Override - public final void destroyItem(ViewGroup container, int position, - Object object) { - View view = (View) object; - container.removeView(view); - int viewType = getItemViewType(position); - if (viewType != IGNORE_ITEM_VIEW_TYPE) { - recycleBin.addScrapView(view, position, viewType); - } - } - - @Override - public final boolean isViewFromObject(View view, Object object) { - return view == object; - } - - /** - *

- * Returns the number of types of Views that will be created by - * {@link #getView}. Each type represents a set of views that can be - * converted in {@link #getView}. If the adapter always returns the same - * type of View for all items, this method should return 1. - *

- *

- * This method will only be called when when the adapter is set on the the - * {@link AdapterView}. - *

- * - * @return The number of types of Views that will be created by this adapter - */ - public int getViewTypeCount() { - return 1; - } - - /** - * Get the type of View that will be created by {@link #getView} for the - * specified item. - * - * @param position - * The position of the item within the adapter's data set whose - * view type we want. - * @return An integer representing the type of View. Two views should share - * the same type if one can be converted to the other in - * {@link #getView}. Note: Integers must be in the range 0 to - * {@link #getViewTypeCount} - 1. {@link #IGNORE_ITEM_VIEW_TYPE} can - * also be returned. - * @see #IGNORE_ITEM_VIEW_TYPE - */ - public int getItemViewType(int position) { - return 0; - } - - /** - * Get a View that displays the data at the specified position in the data - * set. You can either create a View manually or inflate it from an XML - * layout file. When the View is inflated, the parent View (GridView, - * ListView...) will apply default layout parameters unless you use - * {@link android.view.LayoutInflater#inflate(int, android.view.ViewGroup, boolean)} - * to specify a root view and to prevent attachment to the root. - * - * @param position - * The position of the item within the adapter's data set of the - * item whose view we want. - * @param convertView - * The old view to reuse, if possible. Note: You should check - * that this view is non-null and of an appropriate type before - * using. If it is not possible to convert this view to display - * the correct data, this method can create a new view. - * Heterogeneous lists can specify their number of view types, so - * that this View is always of the right type (see - * {@link #getViewTypeCount()} and {@link #getItemViewType(int)} - * ). - * @param parent - * The parent that this view will eventually be attached to - * @return A View corresponding to the data at the specified position. - */ - public abstract View getView(int position, View convertView, - ViewGroup container); -} diff --git a/app/src/main/java/net/oschina/app/adapter/SearchAdapter.java b/app/src/main/java/net/oschina/app/adapter/SearchAdapter.java deleted file mode 100644 index 9e77e3c0b86ede480514a34f114568f9c5d4b984..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/adapter/SearchAdapter.java +++ /dev/null @@ -1,70 +0,0 @@ -package net.oschina.app.adapter; - -import net.oschina.app.R; -import net.oschina.app.base.ListBaseAdapter; -import net.oschina.app.bean.SearchResult; -import net.oschina.app.util.StringUtils; -import android.annotation.SuppressLint; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; -import butterknife.ButterKnife; -import butterknife.InjectView; - -public class SearchAdapter extends ListBaseAdapter { - - @SuppressLint("InflateParams") - @Override - protected View getRealView(int position, View convertView, ViewGroup parent) { - ViewHolder vh = null; - if (convertView == null || convertView.getTag() == null) { - convertView = getLayoutInflater(parent.getContext()).inflate( - R.layout.list_cell_news, null); - vh = new ViewHolder(convertView); - convertView.setTag(vh); - } else { - vh = (ViewHolder) convertView.getTag(); - } - - SearchResult item = (SearchResult) mDatas.get(position); - - vh.title.setText(item.getTitle()); - - if (item.getDescription() == null || StringUtils.isEmpty(item.getDescription())) { - vh.description.setVisibility(View.GONE); - } else { - vh.description.setVisibility(View.VISIBLE); - vh.description.setText(item.getDescription()); - } - - if (!StringUtils.isEmpty(item.getAuthor())) { - vh.source.setText(item.getAuthor()); - } else { - vh.source.setVisibility(View.GONE); - } - - if (!StringUtils.isEmpty(item.getPubDate())) { - vh.time.setText(StringUtils.friendly_time(item.getPubDate())); - } else { - vh.time.setVisibility(View.GONE); - } - - vh.tip.setVisibility(View.GONE); - vh.comment_count.setVisibility(View.GONE); - return convertView; - } - - static class ViewHolder { - @InjectView(R.id.tv_title)TextView title; - @InjectView(R.id.tv_description)TextView description; - @InjectView(R.id.tv_source)TextView source; - @InjectView(R.id.tv_time)TextView time; - @InjectView(R.id.tv_comment_count)TextView comment_count; - @InjectView(R.id.iv_tip)ImageView tip; - - public ViewHolder(View view) { - ButterKnife.inject(this, view); - } - } -} diff --git a/app/src/main/java/net/oschina/app/adapter/SearchFriendAdapter.java b/app/src/main/java/net/oschina/app/adapter/SearchFriendAdapter.java index 313cc6c8703140fb5a651c0c9074d256cf566115..d6e7bea0ed93f7ae65ca5598eb99c86d6cda3e0d 100644 --- a/app/src/main/java/net/oschina/app/adapter/SearchFriendAdapter.java +++ b/app/src/main/java/net/oschina/app/adapter/SearchFriendAdapter.java @@ -18,7 +18,7 @@ import net.oschina.app.widget.AvatarView; import java.util.List; import butterknife.ButterKnife; -import butterknife.InjectView; +import butterknife.Bind; /** *

Created 15/8/27 下午9:29.

@@ -76,15 +76,15 @@ public class SearchFriendAdapter extends BaseAdapter { } static class NormalViewHolder { - @InjectView(R.id.tv_name) + @Bind(R.id.tv_name) TextView name; - @InjectView(R.id.iv_avatar) + @Bind(R.id.iv_avatar) AvatarView avatar; - @InjectView(R.id.cb_check) + @Bind(R.id.cb_check) CheckBox checkBox; NormalViewHolder(View view) { - ButterKnife.inject(this, view); + ButterKnife.bind(this, view); avatar.setClickable(false); } diff --git a/app/src/main/java/net/oschina/app/adapter/SelectFriendAdapter.java b/app/src/main/java/net/oschina/app/adapter/SelectFriendAdapter.java index b2b85e972781371137a62b545c46f9c97e5a3184..b3f3183855f9b095ee572173c39b902ca11d04e6 100644 --- a/app/src/main/java/net/oschina/app/adapter/SelectFriendAdapter.java +++ b/app/src/main/java/net/oschina/app/adapter/SelectFriendAdapter.java @@ -17,7 +17,7 @@ import java.util.ArrayList; import java.util.List; import butterknife.ButterKnife; -import butterknife.InjectView; +import butterknife.Bind; /** *

Created 15/8/26 下午2:09.

@@ -182,11 +182,11 @@ public class SelectFriendAdapter extends BaseAdapter { } static class HeaderViewHolder { - @InjectView(R.id.header_text) + @Bind(R.id.header_text) TextView text; HeaderViewHolder(View view) { - ButterKnife.inject(this, view); + ButterKnife.bind(this, view); } public void bind(String index) { @@ -195,15 +195,15 @@ public class SelectFriendAdapter extends BaseAdapter { } static class NormalViewHolder { - @InjectView(R.id.tv_name) + @Bind(R.id.tv_name) TextView name; - @InjectView(R.id.iv_avatar) + @Bind(R.id.iv_avatar) AvatarView avatar; - @InjectView(R.id.cb_check) + @Bind(R.id.cb_check) CheckBox checkBox; NormalViewHolder(View view) { - ButterKnife.inject(this, view); + ButterKnife.bind(this, view); avatar.setClickable(false); } diff --git a/app/src/main/java/net/oschina/app/adapter/SoftwareAdapter.java b/app/src/main/java/net/oschina/app/adapter/SoftwareAdapter.java index 2aea0ca4d3ae357829cbfe0d7ad42c8493b9dcf2..a33d7f7e07ad41f09a5b71be535c34747ca128a1 100644 --- a/app/src/main/java/net/oschina/app/adapter/SoftwareAdapter.java +++ b/app/src/main/java/net/oschina/app/adapter/SoftwareAdapter.java @@ -12,18 +12,18 @@ import net.oschina.app.bean.SoftwareList; import net.oschina.app.util.ThemeSwitchUtils; import butterknife.ButterKnife; -import butterknife.InjectView; +import butterknife.Bind; public class SoftwareAdapter extends ListBaseAdapter { static class ViewHold { - @InjectView(R.id.tv_title) + @Bind(R.id.tv_title) TextView name; - @InjectView(R.id.tv_software_des) + @Bind(R.id.tv_software_des) TextView des; public ViewHold(View view) { - ButterKnife.inject(this, view); + ButterKnife.bind(this, view); } } @@ -42,8 +42,7 @@ public class SoftwareAdapter extends ListBaseAdapter { SoftwareDec softwareDes = (SoftwareDec) mDatas.get(position); vh.name.setText(softwareDes.getName()); - if (AppContext.isOnReadedPostList(SoftwareList.PREF_READED_SOFTWARE_LIST, - softwareDes.getName())) { + if (false) { vh.name.setTextColor(parent.getContext().getResources() .getColor(ThemeSwitchUtils.getTitleReadedColor())); } else { diff --git a/app/src/main/java/net/oschina/app/adapter/SoftwareCatalogListAdapter.java b/app/src/main/java/net/oschina/app/adapter/SoftwareCatalogListAdapter.java index 68a4b02716ad43bdf64f1f5427285a796ae15e99..ca6be25740e46a39197c40f70996a31ad9684473 100644 --- a/app/src/main/java/net/oschina/app/adapter/SoftwareCatalogListAdapter.java +++ b/app/src/main/java/net/oschina/app/adapter/SoftwareCatalogListAdapter.java @@ -1,39 +1,44 @@ package net.oschina.app.adapter; -import net.oschina.app.R; -import net.oschina.app.base.ListBaseAdapter; -import net.oschina.app.bean.SoftwareCatalogList.SoftwareType; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; + +import net.oschina.app.R; +import net.oschina.app.base.ListBaseAdapter; +import net.oschina.app.bean.SoftwareCatalogList.SoftwareType; + +import butterknife.Bind; import butterknife.ButterKnife; -import butterknife.InjectView; public class SoftwareCatalogListAdapter extends ListBaseAdapter { - - static class ViewHold{ - @InjectView(R.id.tv_software_catalog_name)TextView name; - public ViewHold(View view) { - ButterKnife.inject(this,view); - } - } - - @Override - protected View getRealView(int position, View convertView, ViewGroup parent) { - - ViewHold vh = null; - - if (convertView == null || convertView.getTag() == null) { - convertView = getLayoutInflater(parent.getContext()).inflate(R.layout.list_cell_softwarecatalog, null); - vh = new ViewHold(convertView); - convertView.setTag(vh); - } else { - vh = (ViewHold)convertView.getTag(); - } - - SoftwareType softwareType = (SoftwareType) mDatas.get(position); - vh.name.setText(softwareType.getName()); - return convertView; - - } + + static class ViewHold { + @Bind(R.id.tv_software_catalog_name) + TextView name; + + public ViewHold(View view) { + ButterKnife.bind(this, view); + } + } + + @Override + protected View getRealView(int position, View convertView, ViewGroup parent) { + + ViewHold vh = null; + + if (convertView == null || convertView.getTag() == null) { + convertView = getLayoutInflater(parent.getContext()).inflate(R.layout + .list_cell_softwarecatalog, null); + vh = new ViewHold(convertView); + convertView.setTag(vh); + } else { + vh = (ViewHold) convertView.getTag(); + } + + SoftwareType softwareType = (SoftwareType) mDatas.get(position); + vh.name.setText(softwareType.getName()); + return convertView; + + } } diff --git a/app/src/main/java/net/oschina/app/adapter/TweetAdapter.java b/app/src/main/java/net/oschina/app/adapter/TweetAdapter.java index 8fcb096eac337d80fc1ba44066eacb77eba515db..246a85e7dee4fa431c992eab6da1a3ba40157a91 100644 --- a/app/src/main/java/net/oschina/app/adapter/TweetAdapter.java +++ b/app/src/main/java/net/oschina/app/adapter/TweetAdapter.java @@ -4,11 +4,10 @@ import android.content.Context; import android.content.DialogInterface; import android.graphics.Bitmap; import android.graphics.BitmapFactory; -import android.text.Html; import android.text.Spannable; import android.text.SpannableString; -import android.text.Spanned; import android.text.TextUtils; +import android.text.method.LinkMovementMethod; import android.text.style.ImageSpan; import android.view.View; import android.view.View.OnClickListener; @@ -23,63 +22,54 @@ import net.oschina.app.R; import net.oschina.app.api.remote.OSChinaApi; import net.oschina.app.base.ListBaseAdapter; import net.oschina.app.bean.Tweet; +import net.oschina.app.bean.User; import net.oschina.app.emoji.InputHelper; -import net.oschina.app.ui.ImagePreviewActivity; -import net.oschina.app.util.DialogHelp; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.utils.AssimilateUtils; +import net.oschina.app.improve.utils.DialogHelper; +import net.oschina.app.ui.OSCPhotosActivity; import net.oschina.app.util.ImageUtils; -import net.oschina.app.util.KJAnimations; import net.oschina.app.util.PlatfromUtil; import net.oschina.app.util.StringUtils; -import net.oschina.app.util.TypefaceUtils; import net.oschina.app.util.UIHelper; import net.oschina.app.widget.AvatarView; -import net.oschina.app.widget.MyLinkMovementMethod; import net.oschina.app.widget.TweetTextView; import org.kymjs.kjframe.Core; import org.kymjs.kjframe.utils.DensityUtils; +import java.util.List; + +import butterknife.Bind; import butterknife.ButterKnife; -import butterknife.InjectView; import cz.msebera.android.httpclient.Header; public class TweetAdapter extends ListBaseAdapter { static class ViewHolder { - @InjectView(R.id.tv_tweet_name) + @Bind(R.id.tv_tweet_name) TextView author; - @InjectView(R.id.tv_tweet_time) + @Bind(R.id.tv_tweet_time) TextView time; - @InjectView(R.id.tweet_item) + @Bind(R.id.tweet_item) TweetTextView content; - @InjectView(R.id.tv_tweet_comment_count) + @Bind(R.id.tv_tweet_comment_count) TextView commentcount; - @InjectView(R.id.tv_tweet_platform) + @Bind(R.id.tv_tweet_platform) TextView platform; - @InjectView(R.id.iv_tweet_face) + @Bind(R.id.iv_tweet_face) AvatarView face; - @InjectView(R.id.iv_tweet_image) + @Bind(R.id.iv_tweet_image) ImageView image; - @InjectView(R.id.tv_like_state) - TextView tvLikeState; - @InjectView(R.id.tv_del) - TextView del; - @InjectView(R.id.tv_likeusers) + @Bind(R.id.iv_like_state) + ImageView ivLikeState; + @Bind(R.id.tv_likeusers) TextView likeUsers; + @Bind(R.id.tv_tweet_like_count) + TextView tv_tweet_like_count; public ViewHolder(View view) { - ButterKnife.inject(this, view); - image.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - String url = (String) v.getTag(); - int index = url.lastIndexOf("?"); - if (index > 0) { - url = url.substring(0, index); - } - ImagePreviewActivity.showImagePrivew(v.getContext(), 0, new String[]{url}); - } - }); + ButterKnife.bind(this, view); } } @@ -100,7 +90,7 @@ public class TweetAdapter extends ListBaseAdapter { private void initRecordImg(Context cxt) { recordBitmap = BitmapFactory.decodeResource(cxt.getResources(), - R.drawable.audio3); + R.mipmap.audio3); recordBitmap = ImageUtils.zoomBitmap(recordBitmap, DensityUtils.dip2px(cxt, 20f), DensityUtils.dip2px(cxt, 20f)); } @@ -110,7 +100,7 @@ public class TweetAdapter extends ListBaseAdapter { context = parent.getContext(); final ViewHolder vh; if (convertView == null || convertView.getTag() == null) { - convertView = View.inflate(context, R.layout.list_cell_tweet, null); + convertView = View.inflate(context, R.layout.item_list_tweet, null); vh = new ViewHolder(convertView); convertView.setTag(vh); } else { @@ -118,28 +108,32 @@ public class TweetAdapter extends ListBaseAdapter { } final Tweet tweet = mDatas.get(position); - if (tweet.getAuthorid() == AppContext.getInstance().getLoginUid()) { - vh.del.setVisibility(View.VISIBLE); - vh.del.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - optionDel(context, tweet, position); - } - }); - } else { - vh.del.setVisibility(View.GONE); - } +// if (tweet.getAuthorid() == AppContext.getInstance().getLoginUid()) { +// vh.del.setVisibility(View.VISIBLE); +// vh.del.setOnClickListener(new OnClickListener() { +// @Override +// public void onClick(View v) { +// optionDel(context, tweet, position); +// } +// }); +// } else { +// vh.del.setVisibility(View.GONE); +// } vh.face.setUserInfo(tweet.getAuthorid(), tweet.getAuthor()); vh.face.setAvatarUrl(tweet.getPortrait()); vh.author.setText(tweet.getAuthor()); - vh.time.setText(StringUtils.friendly_time(tweet.getPubDate())); - vh.content.setMovementMethod(MyLinkMovementMethod.a()); + vh.time.setText(StringUtils.formatSomeAgo(tweet.getPubDate())); + vh.tv_tweet_like_count.setText(String.valueOf(tweet.getLikeCount())); + + vh.content.setMovementMethod(LinkMovementMethod.getInstance()); vh.content.setFocusable(false); vh.content.setDispatchToParent(true); vh.content.setLongClickable(false); - - Spanned span = Html.fromHtml(tweet.getBody().trim()); + Spannable spannable = AssimilateUtils.assimilateOnlyLink(context, tweet.getBody()); + spannable = AssimilateUtils.assimilateOnlyAtUser(context, spannable); + spannable = AssimilateUtils.assimilateOnlyTag(context, spannable); + spannable = InputHelper.displayEmoji(context.getResources(), spannable); if (!StringUtils.isEmpty(tweet.getAttach())) { if (recordBitmap == null) { @@ -149,41 +143,46 @@ public class TweetAdapter extends ListBaseAdapter { SpannableString str = new SpannableString("c"); str.setSpan(recordImg, 0, 1, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); vh.content.setText(str); - span = InputHelper.displayEmoji(context.getResources(), span); - vh.content.append(span); + vh.content.append(spannable); } else { - span = InputHelper.displayEmoji(context.getResources(), span); - vh.content.setText(span); + vh.content.setText(spannable); } vh.commentcount.setText(tweet.getCommentCount()); - showTweetImage(vh, tweet.getImgSmall(), tweet.getImgBig()); - tweet.setLikeUsers(context, vh.likeUsers, true); - - if (tweet.getLikeUser() == null) { - vh.tvLikeState.setVisibility(View.GONE); + if (TextUtils.isEmpty(tweet.getImgSmall())) { + vh.image.setVisibility(View.GONE); } else { - vh.tvLikeState.setOnClickListener(new OnClickListener() { + vh.image.setVisibility(View.VISIBLE); + new Core.Builder().view(vh.image).size(300, 300).url(tweet.getImgSmall() + "?300X300") + .loadBitmapRes(R.drawable.pic_bg).doTask(); + vh.image.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - if (AppContext.getInstance().isLogin()) { - updateLikeState(vh, tweet); - } else { - AppContext.showToast("先登陆再赞~"); - UIHelper.showLoginActivity(context); - } + OSCPhotosActivity.showImagePreview(context, tweet.getImgBig()); } }); } - TypefaceUtils.setTypeface(vh.tvLikeState); + tweet.setLikeUsers(context, vh.likeUsers, true); + + vh.ivLikeState.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (AccountHelper.isLogin()) { + updateLikeState(vh, tweet); + } else { + AppContext.showToast("先登陆再赞~"); + UIHelper.showLoginActivity(context); + } + } + }); + +// TypefaceUtils.setTypeface(vh.tvLikeState); if (tweet.getIsLike() == 1) { - vh.tvLikeState.setTextColor(AppContext.getInstance().getResources().getColor(R.color - .day_colorPrimary)); + vh.ivLikeState.setImageResource(R.mipmap.ic_thumbup_actived); } else { - vh.tvLikeState.setTextColor(AppContext.getInstance().getResources().getColor(R.color - .gray)); + vh.ivLikeState.setImageResource(R.mipmap.ic_thumb_normal); } PlatfromUtil.setPlatFromString(vh.platform, tweet.getAppclient()); return convertView; @@ -196,25 +195,30 @@ public class TweetAdapter extends ListBaseAdapter { if (!tweet.getLikeUser().isEmpty()) { tweet.getLikeUser().remove(0); } - OSChinaApi.pubUnLikeTweet(tweet.getId(), tweet.getAuthorid(), - handler); - vh.tvLikeState.setTextColor(AppContext.getInstance().getResources().getColor(R.color - .gray)); + OSChinaApi.pubUnLikeTweet(tweet.getId(), tweet.getAuthorid(), handler); +// vh.ivLikeState.setTextColor(AppContext.getInstance().getResources().getColor(R.color +// .gray)); + vh.ivLikeState.setImageResource(R.mipmap.ic_thumb_normal); } else { - vh.tvLikeState.setAnimation(KJAnimations.getScaleAnimation(1.5f, 300)); - tweet.getLikeUser().add(0, AppContext.getInstance().getLoginUser()); + //vh.tvLikeState.setAnimation(KJAnimations.getScaleAnimation(1.5f, 300)); + List likeUser = tweet.getLikeUser(); + if (likeUser!=null) + //tweet.getLikeUser().add(0, AppContext.getInstance().getLoginUser()); OSChinaApi.pubLikeTweet(tweet.getId(), tweet.getAuthorid(), handler); - vh.tvLikeState.setTextColor(AppContext.getInstance().getResources().getColor(R.color - .day_colorPrimary)); +// vh.tvLikeState.setTextColor(AppContext.getInstance().getResources().getColor(R.color +// .day_colorPrimary)); + vh.ivLikeState.setImageResource(R.mipmap.ic_thumbup_actived); tweet.setIsLike(1); tweet.setLikeCount(tweet.getLikeCount() + 1); } + vh.tv_tweet_like_count.setText(String.valueOf(tweet.getLikeCount())); tweet.setLikeUsers(context, vh.likeUsers, true); } + @SuppressWarnings("unused") private void optionDel(Context context, final Tweet tweet, final int position) { - DialogHelp.getConfirmDialog(context, "确定删除吗?", new DialogInterface.OnClickListener() { + DialogHelper.getConfirmDialog(context, "确定删除吗?", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { OSChinaApi.deleteTweet(tweet.getAuthorid(), tweet.getId(), @@ -234,18 +238,4 @@ public class TweetAdapter extends ListBaseAdapter { } }).show(); } - - /** - * 动态设置动弹列表图片显示规则 - */ - private void showTweetImage(final ViewHolder vh, String imgSmall, final String imgBig) { - if (!TextUtils.isEmpty(imgBig)) { - vh.image.setTag(imgBig); - new Core.Builder().view(vh.image).size(300, 300).url(imgBig + "?300X300") - .loadBitmapRes(R.drawable.pic_bg).doTask(); - vh.image.setVisibility(AvatarView.VISIBLE); - } else { - vh.image.setVisibility(AvatarView.GONE); - } - } } diff --git a/app/src/main/java/net/oschina/app/adapter/TweetLikeAdapter.java b/app/src/main/java/net/oschina/app/adapter/TweetLikeAdapter.java index 2dc6aa678e1621568112a25b4b9b3ddad07960ee..c00390a5edfdd8b8c838462f9e2edd26e45426a7 100644 --- a/app/src/main/java/net/oschina/app/adapter/TweetLikeAdapter.java +++ b/app/src/main/java/net/oschina/app/adapter/TweetLikeAdapter.java @@ -18,7 +18,7 @@ import net.oschina.app.widget.MyURLSpan; import net.oschina.app.widget.TweetTextView; import butterknife.ButterKnife; -import butterknife.InjectView; +import butterknife.Bind; /** * 动弹点赞适配器 TweetLikeAdapter.java @@ -48,7 +48,7 @@ public class TweetLikeAdapter extends ListBaseAdapter { vh.action.setText("赞了我的动弹"); - vh.time.setText(StringUtils.friendly_time(item.getDatatime().trim())); + vh.time.setText(StringUtils.formatSomeAgo(item.getDatatime().trim())); PlatfromUtil.setPlatFromString(vh.from, item.getAppClient()); vh.avatar.setUserInfo(item.getUser().getId(), item.getUser().getName()); @@ -67,21 +67,21 @@ public class TweetLikeAdapter extends ListBaseAdapter { } static class ViewHolder { - @InjectView(R.id.tv_name) + @Bind(R.id.tv_name) TextView name; - @InjectView(R.id.tv_from) + @Bind(R.id.tv_from) TextView from; - @InjectView(R.id.tv_time) + @Bind(R.id.tv_time) TextView time; - @InjectView(R.id.tv_action) + @Bind(R.id.tv_action) TextView action; - @InjectView(R.id.tv_reply) + @Bind(R.id.tv_reply) TweetTextView reply; - @InjectView(R.id.iv_avatar) + @Bind(R.id.iv_avatar) AvatarView avatar; public ViewHolder(View view) { - ButterKnife.inject(this, view); + ButterKnife.bind(this, view); } } } diff --git a/app/src/main/java/net/oschina/app/adapter/TweetLikeUsersAdapter.java b/app/src/main/java/net/oschina/app/adapter/TweetLikeUsersAdapter.java index 96110041bf15d11281f5e348d6ec55b420bcfed4..01ca8c84a61b95220d2750c9e5f5209eb24b5bac 100644 --- a/app/src/main/java/net/oschina/app/adapter/TweetLikeUsersAdapter.java +++ b/app/src/main/java/net/oschina/app/adapter/TweetLikeUsersAdapter.java @@ -1,16 +1,17 @@ package net.oschina.app.adapter; -import butterknife.ButterKnife; -import butterknife.InjectView; - import android.view.View; import android.view.ViewGroup; import android.widget.TextView; + import net.oschina.app.R; import net.oschina.app.base.ListBaseAdapter; import net.oschina.app.bean.User; import net.oschina.app.widget.AvatarView; +import butterknife.Bind; +import butterknife.ButterKnife; + /** * TweetLikeUsersAdapter.java * @@ -40,13 +41,13 @@ public class TweetLikeUsersAdapter extends ListBaseAdapter { static class ViewHolder { - @InjectView(R.id.iv_avatar) + @Bind(R.id.iv_avatar) AvatarView avatar; - @InjectView(R.id.tv_name) + @Bind(R.id.tv_name) TextView name; public ViewHolder(View view) { - ButterKnife.inject(this, view); + ButterKnife.bind(this, view); } } } diff --git a/app/src/main/java/net/oschina/app/adapter/UserFavoriteAdapter.java b/app/src/main/java/net/oschina/app/adapter/UserFavoriteAdapter.java index 405820f3e1f5c68f107ae293a523de19f049fe8d..6dd22b7abc64fbdac4587c7429324562cce1bf73 100644 --- a/app/src/main/java/net/oschina/app/adapter/UserFavoriteAdapter.java +++ b/app/src/main/java/net/oschina/app/adapter/UserFavoriteAdapter.java @@ -1,41 +1,44 @@ package net.oschina.app.adapter; -import net.oschina.app.R; -import net.oschina.app.base.ListBaseAdapter; -import net.oschina.app.bean.Favorite; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; + +import net.oschina.app.R; +import net.oschina.app.base.ListBaseAdapter; +import net.oschina.app.bean.Favorite; + +import butterknife.Bind; import butterknife.ButterKnife; -import butterknife.InjectView; public class UserFavoriteAdapter extends ListBaseAdapter { - - static class ViewHolder { - - @InjectView(R.id.tv_favorite_title) TextView title; - - public ViewHolder(View view) { - ButterKnife.inject(this,view); - } - } - - @Override - protected View getRealView(int position, View convertView, ViewGroup parent) { - ViewHolder vh = null; - if (convertView == null || convertView.getTag() == null) { - convertView = getLayoutInflater(parent.getContext()).inflate( - R.layout.list_cell_favorite, null); - vh = new ViewHolder(convertView); - convertView.setTag(vh); - } else { - vh = (ViewHolder) convertView.getTag(); - } - - Favorite favorite = (Favorite) mDatas.get(position); - - vh.title.setText(favorite.getTitle()); - return convertView; - } + + static class ViewHolder { + + @Bind(R.id.tv_favorite_title) + TextView title; + + public ViewHolder(View view) { + ButterKnife.bind(this, view); + } + } + + @Override + protected View getRealView(int position, View convertView, ViewGroup parent) { + ViewHolder vh = null; + if (convertView == null || convertView.getTag() == null) { + convertView = getLayoutInflater(parent.getContext()).inflate( + R.layout.list_cell_favorite, null); + vh = new ViewHolder(convertView); + convertView.setTag(vh); + } else { + vh = (ViewHolder) convertView.getTag(); + } + + Favorite favorite = (Favorite) mDatas.get(position); + + vh.title.setText(favorite.getTitle()); + return convertView; + } } diff --git a/app/src/main/java/net/oschina/app/adapter/ViewHolder.java b/app/src/main/java/net/oschina/app/adapter/ViewHolder.java new file mode 100644 index 0000000000000000000000000000000000000000..73147f5861fe227cd70fe3b5e9bc7a3f05ab4797 --- /dev/null +++ b/app/src/main/java/net/oschina/app/adapter/ViewHolder.java @@ -0,0 +1,237 @@ +package net.oschina.app.adapter; + +import android.text.SpannableString; +import android.text.Spanned; +import android.text.TextUtils; +import android.util.SparseArray; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; + +import com.bumptech.glide.RequestManager; + +import net.oschina.app.R; +import net.oschina.app.util.ImageLoader; + +@SuppressWarnings("unused") +public class ViewHolder { + private SparseArray mViews; + private int mLayoutId; + private View mConvertView; + private int mPosition; + private Callback mCaller; + + public interface Callback { + RequestManager getImgLoader(); + + LayoutInflater getInflate(); + } + + + public ViewHolder(Callback caller, ViewGroup parent, int layoutId, int position) { + this.mViews = new SparseArray(); + this.mPosition = position; + this.mLayoutId = layoutId; + this.mCaller = caller; + LayoutInflater inflater = caller.getInflate(); + this.mConvertView = inflater.inflate(layoutId, parent, false); + this.mConvertView.setTag(this); + } + + /** + * 获取一个viewHolder + * + * @param caller Caller + * @param convertView view + * @param parent parent view + * @param layoutId 布局资源id + * @param position 索引 + * @return + */ + public static ViewHolder getViewHolder(Callback caller, View convertView, ViewGroup parent, int layoutId, int position) { + boolean needCreateView = false; + ViewHolder vh = null; + if (convertView == null) { + needCreateView = true; + } else { + vh = (ViewHolder) convertView.getTag(); + } + if (vh != null && (vh.mLayoutId != layoutId)) { + needCreateView = true; + } + if (needCreateView) { + return new ViewHolder(caller, parent, layoutId, position); + } + return (ViewHolder) convertView.getTag(); + } + + public int getPosition() { + return this.mPosition; + } + + public int getLayoutId() { + return mLayoutId; + } + + // 通过一个viewId来获取一个view + public T getView(int viewId) { + View view = mViews.get(viewId); + if (view == null) { + view = mConvertView.findViewById(viewId); + mViews.put(viewId, view); + } + return (T) view; + } + + // 返回viewHolder的容器类 + public View getConvertView() { + return this.mConvertView; + } + + // 给TextView设置文字 + public void setText(int viewId, String text) { + if (TextUtils.isEmpty(text)) return; + TextView tv = getView(viewId); + tv.setText(text); + tv.setVisibility(View.VISIBLE); + } + + // 给TextView设置文字 + public void setText(int viewId, SpannableString text) { + if (text == null) return; + TextView tv = getView(viewId); + tv.setText(text); + tv.setVisibility(View.VISIBLE); + } + + public void setTextColor(int viewId, int textColor) { + TextView tv = getView(viewId); + tv.setTextColor(textColor); + tv.setVisibility(View.VISIBLE); + } + + public void setText(int viewId, Spanned text) { + if (text == null) return; + TextView tv = getView(viewId); + tv.setText(text); + tv.setVisibility(View.VISIBLE); + } + + // 给TextView设置文字 + public void setText(int viewId, int textRes) { + TextView tv = getView(viewId); + tv.setText(textRes); + tv.setVisibility(View.VISIBLE); + } + + public void setText(int viewId, int textRes, int bgRes, int textColor) { + TextView tv = getView(viewId); + tv.setText(textRes); + tv.setVisibility(View.VISIBLE); + tv.setBackgroundResource(bgRes); + tv.setTextColor(textColor); + } + + public void setText(int viewId, String text, boolean gone) { + if (TextUtils.isEmpty(text) && gone) { + getView(viewId).setVisibility(View.GONE); + return; + } + setText(viewId, text); + } + + public void setText(int viewId, String text, int emptyRes) { + TextView tv = getView(viewId); + if (TextUtils.isEmpty(text)) { + tv.setText(emptyRes); + } else { + tv.setText(text); + } + tv.setVisibility(View.VISIBLE); + } + + public void setText(int viewId, String text, String emptyText) { + TextView tv = getView(viewId); + if (TextUtils.isEmpty(text)) { + tv.setText(emptyText); + } else { + tv.setText(text); + } + tv.setVisibility(View.VISIBLE); + } + + public void setImage(int viewId, int imgRes) { + ImageView iv = getView(viewId); + iv.setImageResource(imgRes); + } + + public void setImageForNet(int viewId, String imgUrl, int emptyRes) { + ImageView iv = getView(viewId); + RequestManager loader = mCaller.getImgLoader(); + ImageLoader.loadImage(loader, iv, imgUrl, emptyRes); + } + + public void setImageForNet(ImageView iv, String imgUrl, int emptyRes) { + RequestManager loader = mCaller.getImgLoader(); + ImageLoader.loadImage(loader, iv, imgUrl, emptyRes); + } + + public void setImageForNet(ImageView iv, String imgUrl, int emptyRes, int errorRes) { + RequestManager loader = mCaller.getImgLoader(); + ImageLoader.loadImage(loader, iv, imgUrl, emptyRes, errorRes); + } + + public void setImageForNet(int viewId, String imgUrl) { + setImageForNet(viewId, imgUrl, R.drawable.bg_normal); + } + + // 设置头像 + public void setPortrait(int viewId, String imgUrl) { + setImageForNet(viewId, imgUrl, R.drawable.bg_normal); + } + + public void setButtonText(int viewId, String text) { + Button button = getView(viewId); + button.setText(text); + } + + public void setOnClick(int viewId, View.OnClickListener onClickListener) { + View view = getView(viewId); + view.setOnClickListener(onClickListener); + } + + public void setGone(int viewId) { + getView(viewId).setVisibility(View.GONE); + } + + public void setVisibility(int viewId) { + getView(viewId).setVisibility(View.VISIBLE); + } + + public void setInVisibility(int viewId) { + getView(viewId).setVisibility(View.INVISIBLE); + } + + public boolean isVisibility(int viewId) { + return (getView(viewId).getVisibility()) == View.VISIBLE; + } + + public void setEnabled(int viewId) { + View view = getView(viewId); + view.setEnabled(true); + } + + public void setEnabled(int viewId, boolean isEnable) { + View view = getView(viewId); + view.setEnabled(isEnable); + } + + public void setDisEnabled(int viewId) { + View view = getView(viewId); + view.setEnabled(false); + } + +} \ No newline at end of file diff --git a/app/src/main/java/net/oschina/app/adapter/ViewPageFragmentAdapter.java b/app/src/main/java/net/oschina/app/adapter/ViewPageFragmentAdapter.java index e216768150fde748f7c538d659053a2ca95c4800..defeb38fdf574d5807e510e758d601087c57cd19 100644 --- a/app/src/main/java/net/oschina/app/adapter/ViewPageFragmentAdapter.java +++ b/app/src/main/java/net/oschina/app/adapter/ViewPageFragmentAdapter.java @@ -1,31 +1,36 @@ package net.oschina.app.adapter; -import java.util.ArrayList; - -import net.oschina.app.R; -import net.oschina.app.widget.PagerSlidingTabStrip; import android.annotation.SuppressLint; import android.content.Context; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentStatePagerAdapter; +import android.support.v4.util.ArrayMap; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; +import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.widget.TextView; +import net.oschina.app.R; +import net.oschina.app.widget.PagerSlidingTabStrip; + +import java.util.ArrayList; +import java.util.Map; + @SuppressLint("Recycle") public class ViewPageFragmentAdapter extends FragmentStatePagerAdapter { private final Context mContext; protected PagerSlidingTabStrip mPagerStrip; private final ViewPager mViewPager; - private final ArrayList mTabs = new ArrayList(); + public ArrayList mTabs = new ArrayList(); + private Map mFragments = new ArrayMap<>(); public ViewPageFragmentAdapter(FragmentManager fm, - PagerSlidingTabStrip pageStrip, ViewPager pager) { + PagerSlidingTabStrip pageStrip, ViewPager pager) { super(fm); mContext = pager.getContext(); mPagerStrip = pageStrip; @@ -50,12 +55,14 @@ public class ViewPageFragmentAdapter extends FragmentStatePagerAdapter { return; } + if (!TextUtils.isEmpty(info.title)) { // 加入tab title View v = LayoutInflater.from(mContext).inflate( R.layout.base_viewpage_fragment_tab_item, null, false); TextView title = (TextView) v.findViewById(R.id.tab_title); title.setText(info.title); mPagerStrip.addTab(v); + } mTabs.add(info); notifyDataSetChanged(); @@ -70,9 +77,8 @@ public class ViewPageFragmentAdapter extends FragmentStatePagerAdapter { /** * 移除一个tab - * - * @param index - * 备注:如果index小于0,则从第一个开始删 如果大于tab的数量值则从最后一个开始删除 + * + * @param index 备注:如果index小于0,则从第一个开始删 如果大于tab的数量值则从最后一个开始删除 */ public void remove(int index) { if (mTabs.isEmpty()) { @@ -84,6 +90,12 @@ public class ViewPageFragmentAdapter extends FragmentStatePagerAdapter { if (index >= mTabs.size()) { index = mTabs.size() - 1; } + + ViewPageInfo info = mTabs.get(index); + // 清理缓存 + if (mFragments.containsKey(info.tag)) + mFragments.remove(info.tag); + mTabs.remove(index); mPagerStrip.removeTab(index, 1); notifyDataSetChanged(); @@ -96,6 +108,7 @@ public class ViewPageFragmentAdapter extends FragmentStatePagerAdapter { if (mTabs.isEmpty()) { return; } + mFragments.clear(); mPagerStrip.removeAllTab(); mTabs.clear(); notifyDataSetChanged(); @@ -114,7 +127,15 @@ public class ViewPageFragmentAdapter extends FragmentStatePagerAdapter { @Override public Fragment getItem(int position) { ViewPageInfo info = mTabs.get(position); - return Fragment.instantiate(mContext, info.clss.getName(), info.args); + + Fragment fragment = mFragments.get(info.tag); + if (fragment == null) { + fragment = Fragment.instantiate(mContext, info.clss.getName(), info.args); + // 避免重复创建而进行缓存 + mFragments.put(info.tag, fragment); + } + + return fragment; } @Override diff --git a/app/src/main/java/net/oschina/app/api/ApiClientHelper.java b/app/src/main/java/net/oschina/app/api/ApiClientHelper.java index f6da3026481e84c4c39d322bbb664e9d76ef2374..ca693668e82bbba8b0c8d1ef0becff5954db0408 100644 --- a/app/src/main/java/net/oschina/app/api/ApiClientHelper.java +++ b/app/src/main/java/net/oschina/app/api/ApiClientHelper.java @@ -1,22 +1,93 @@ package net.oschina.app.api; +import android.app.Application; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.os.Build; +import android.text.TextUtils; + +import net.oschina.app.AppConfig; import net.oschina.app.AppContext; -public class ApiClientHelper { - - /** - * 获得请求的服务端数据的userAgent - * @param appContext - * @return - */ - public static String getUserAgent(AppContext appContext) { - StringBuilder ua = new StringBuilder("OSChina.NET"); - ua.append('/' + appContext.getPackageInfo().versionName + '_' - + appContext.getPackageInfo().versionCode);// app版本信息 - ua.append("/Android");// 手机系统平台 - ua.append("/" + android.os.Build.VERSION.RELEASE);// 手机系统版本 - ua.append("/" + android.os.Build.MODEL); // 手机型号 - ua.append("/" + appContext.getAppId());// 客户端唯一标识 - return ua.toString(); - } +import java.util.UUID; + +class ApiClientHelper { + + /** + * 获得请求的服务端数据的userAgent + * 客户端唯一标识 + * + * @param appContext + * @return + */ + static String getUserAgent(Application appContext) { + // WebSettings.getDefaultUserAgent(appContext) + + int vCode = getPackageInfo(appContext).versionCode; + String version = Build.VERSION.RELEASE; // "1.0" or "3.4b5" + String osVer = version.length() > 0 ? version : "1.0"; + + String model = Build.MODEL; + String id = Build.ID; // "MASTER" or "M4-rc20" + if (id.length() > 0) { + model += " Build/" + id; + } + + String format = "OSChina.NET/1.0 (oscapp; %s; Android %s; %s; %s)"; + String ua = String.format(format, vCode, osVer, model, getAppId(appContext)); + ApiHttpClient.log("getUserAgent:" + ua); + return ua; + } + + public static String getDefaultUserAgent() { + StringBuilder result = new StringBuilder(64); + result.append("Dalvik/"); + result.append(System.getProperty("java.vm.version")); // such as 1.1.0 + result.append(" (Linux; U; Android "); + + String version = Build.VERSION.RELEASE; // "1.0" or "3.4b5" + result.append(version.length() > 0 ? version : "1.0"); + + // add the model for the release build + if ("REL".equals(Build.VERSION.CODENAME)) { + String model = Build.MODEL; + if (model.length() > 0) { + result.append("; "); + result.append(model); + } + } + String id = Build.ID; // "MASTER" or "M4-rc20" + if (id.length() > 0) { + result.append(" Build/"); + result.append(id); + } + result.append(")"); + return result.toString(); + } + + private static String getAppId(Application context) { + if (context instanceof AppContext) { + AppContext appContext = (AppContext) context; + String uniqueID = appContext.getProperty(AppConfig.CONF_APP_UNIQUEID); + if (TextUtils.isEmpty(uniqueID)) { + uniqueID = UUID.randomUUID().toString(); + appContext.setProperty(AppConfig.CONF_APP_UNIQUEID, uniqueID); + } + return uniqueID; + } + return UUID.randomUUID().toString(); + } + + private static PackageInfo getPackageInfo(Application context) { + PackageInfo info = null; + try { + info = context.getPackageManager() + .getPackageInfo(context.getPackageName(), 0); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(System.err); + } + if (info == null) + info = new PackageInfo(); + return info; + } } diff --git a/app/src/main/java/net/oschina/app/api/ApiHttpClient.java b/app/src/main/java/net/oschina/app/api/ApiHttpClient.java index 47e124aff7a4da23d0e3d9488cee70197dca2a3c..6456d9c55b55025352a9420927a8e7437a234fd3 100644 --- a/app/src/main/java/net/oschina/app/api/ApiHttpClient.java +++ b/app/src/main/java/net/oschina/app/api/ApiHttpClient.java @@ -1,60 +1,86 @@ package net.oschina.app.api; -import android.content.Context; -import android.util.Log; -import cz.msebera.android.httpclient.client.params.ClientPNames; +import android.annotation.SuppressLint; +import android.app.Application; +import android.text.TextUtils; import com.loopj.android.http.AsyncHttpClient; import com.loopj.android.http.AsyncHttpResponseHandler; import com.loopj.android.http.RequestParams; import net.oschina.app.AppContext; +import net.oschina.app.improve.account.AccountHelper; import net.oschina.app.util.TLog; +import net.oschina.common.verify.Verifier; +import java.io.IOException; +import java.net.Socket; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; import java.util.Locale; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +import cz.msebera.android.httpclient.Header; +import cz.msebera.android.httpclient.client.CookieStore; +import cz.msebera.android.httpclient.client.params.ClientPNames; +import cz.msebera.android.httpclient.client.protocol.HttpClientContext; +import cz.msebera.android.httpclient.conn.ssl.SSLSocketFactory; +import cz.msebera.android.httpclient.cookie.Cookie; +import cz.msebera.android.httpclient.protocol.HttpContext; + +@SuppressWarnings("WeakerAccess") public class ApiHttpClient { public final static String HOST = "www.oschina.net"; - private static String API_URL = "http://www.oschina.net/%s"; -// public final static String HOST = "192.168.1.101"; -// private static String API_URL = "http://192.168.1.101/%s"; - public static final String DELETE = "DELETE"; - public static final String GET = "GET"; - public static final String POST = "POST"; - public static final String PUT = "PUT"; - public static AsyncHttpClient client; + //public final static String HOST = "www.oschina.tk"; + private static String API_URL = "https://www.oschina.net/%s"; + //private static String API_URL = "http://192.168.1.10/%s"; + private static AsyncHttpClient CLIENT; - public ApiHttpClient() { + private ApiHttpClient() { } - public static AsyncHttpClient getHttpClient() { - return client; + /** + * 初始化网络请求,包括Cookie的初始化 + * + * @param context AppContext + */ + public static void init(Application context) { + CLIENT = null; + AsyncHttpClient client = new AsyncHttpClient(); + //client.setCookieStore(new PersistentCookieStore(context)); + // Set + ApiHttpClient.setHttpClient(client, context); + // Set Cookie + setCookieHeader(AccountHelper.getCookie()); } - public static void cancelAll(Context context) { - client.cancelRequests(context, true); - } - - public static void clearUserCookies(Context context) { - // (new HttpClientCookieStore(context)).a(); + public static AsyncHttpClient getHttpClient() { + return CLIENT; } public static void delete(String partUrl, AsyncHttpResponseHandler handler) { - client.delete(getAbsoluteApiUrl(partUrl), handler); - log(new StringBuilder("DELETE ").append(partUrl).toString()); + CLIENT.delete(getAbsoluteApiUrl(partUrl), handler); + log("DELETE " + partUrl); } public static void get(String partUrl, AsyncHttpResponseHandler handler) { - client.get(getAbsoluteApiUrl(partUrl), handler); - log(new StringBuilder("GET ").append(partUrl).toString()); + CLIENT.get(getAbsoluteApiUrl(partUrl), handler); + log("GET " + partUrl); } public static void get(String partUrl, RequestParams params, AsyncHttpResponseHandler handler) { - client.get(getAbsoluteApiUrl(partUrl), params, handler); - log(new StringBuilder("GET ").append(partUrl).append("&") - .append(params).toString()); + CLIENT.get(getAbsoluteApiUrl(partUrl), params, handler); + log("GET " + partUrl + "?" + params); } public static String getAbsoluteApiUrl(String partUrl) { @@ -62,88 +88,193 @@ public class ApiHttpClient { if (!partUrl.startsWith("http:") && !partUrl.startsWith("https:")) { url = String.format(API_URL, partUrl); } - Log.d("BASE_CLIENT", "request:" + url); + log("request:" + url); return url; } - public static String getApiUrl() { - return API_URL; - } - public static void getDirect(String url, AsyncHttpResponseHandler handler) { - client.get(url, handler); - log(new StringBuilder("GET ").append(url).toString()); + CLIENT.get(url, handler); + log("GET " + url); } public static void log(String log) { - Log.d("BaseApi", log); - TLog.log("Test", log); + TLog.log("ApiHttpClient", log); } public static void post(String partUrl, AsyncHttpResponseHandler handler) { - client.post(getAbsoluteApiUrl(partUrl), handler); - log(new StringBuilder("POST ").append(partUrl).toString()); + CLIENT.post(getAbsoluteApiUrl(partUrl), handler); + log("POST " + partUrl); } public static void post(String partUrl, RequestParams params, AsyncHttpResponseHandler handler) { - client.post(getAbsoluteApiUrl(partUrl), params, handler); - log(new StringBuilder("POST ").append(partUrl).append("&") - .append(params).toString()); - } - - public static void postDirect(String url, RequestParams params, - AsyncHttpResponseHandler handler) { - client.post(url, params, handler); - log(new StringBuilder("POST ").append(url).append("&").append(params) - .toString()); + CLIENT.post(getAbsoluteApiUrl(partUrl), params, handler); + log("POST " + partUrl + "?" + params); } public static void put(String partUrl, AsyncHttpResponseHandler handler) { - client.put(getAbsoluteApiUrl(partUrl), handler); - log(new StringBuilder("PUT ").append(partUrl).toString()); + CLIENT.put(getAbsoluteApiUrl(partUrl), handler); + log("PUT " + partUrl); } public static void put(String partUrl, RequestParams params, AsyncHttpResponseHandler handler) { - client.put(getAbsoluteApiUrl(partUrl), params, handler); - log(new StringBuilder("PUT ").append(partUrl).append("&") - .append(params).toString()); + CLIENT.put(getAbsoluteApiUrl(partUrl), params, handler); + log("PUT " + partUrl + "?" + params); } - public static void setApiUrl(String apiUrl) { - API_URL = apiUrl; + public static void setHttpClient(AsyncHttpClient c, Application application) { + c.addHeader("Accept-Language", Locale.getDefault().toString()); + c.addHeader("Host", HOST); + c.addHeader("Connection", "Keep-Alive"); + //noinspection deprecation + c.getHttpClient().getParams() + .setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, true); + // Set AppToken + c.addHeader("AppToken", Verifier.getPrivateToken(application)); + // setUserAgent + c.setUserAgent(ApiClientHelper.getUserAgent(AppContext.getInstance())); + CLIENT = c; + initSSL(CLIENT); } - public static void setHttpClient(AsyncHttpClient c) { - client = c; - client.addHeader("Accept-Language", Locale.getDefault().toString()); - client.addHeader("Host", HOST); - client.addHeader("Connection", "Keep-Alive"); - client.getHttpClient().getParams() - .setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, true); + public static void setCookieHeader(String cookie) { + if (!TextUtils.isEmpty(cookie)) + CLIENT.addHeader("Cookie", cookie); + log("setCookieHeader:" + cookie); + } - setUserAgent(ApiClientHelper.getUserAgent(AppContext.getInstance())); + /** + * 销毁当前AsyncHttpClient 并重新初始化网络参数,初始化Cookie等信息 + * + * @param appContext AppContext + */ + public static void destroyAndRestore(Application appContext) { + cleanCookie(); + CLIENT = null; + init(appContext); } - public static void setUserAgent(String userAgent) { - client.setUserAgent(userAgent); + public static void cleanCookie() { + // first clear store + // new PersistentCookieStore(AppContext.getInstance()).clear(); + // clear header + AsyncHttpClient client = CLIENT; + if (client != null) { + HttpContext httpContext = client.getHttpContext(); + CookieStore cookies = (CookieStore) httpContext + .getAttribute(HttpClientContext.COOKIE_STORE); + // 清理Async本地存储 + if (cookies != null) { + cookies.clear(); + } + // 清理当前正在使用的Cookie + client.removeHeader("Cookie"); + } + log("cleanCookie"); } - public static void setCookie(String cookie) { - client.addHeader("Cookie", cookie); + /** + * 从AsyncHttpClient自带缓存中获取CookieString + * + * @param client AsyncHttpClient + * @return CookieString + */ + private static String getClientCookie(AsyncHttpClient client) { + String cookie = ""; + if (client != null) { + HttpContext httpContext = client.getHttpContext(); + CookieStore cookies = (CookieStore) httpContext + .getAttribute(HttpClientContext.COOKIE_STORE); + + if (cookies != null && cookies.getCookies() != null && cookies.getCookies().size() > 0) { + for (Cookie c : cookies.getCookies()) { + cookie += (c.getName() + "=" + c.getValue()) + ";"; + } + } + } + log("getClientCookie:" + cookie); + return cookie; } - private static String appCookie; + /** + * 得到当前的网络请求Cookie, + * 登录后触发 + * + * @param headers Header + */ + public static String getCookie(Header[] headers) { + String cookie = getClientCookie(ApiHttpClient.getHttpClient()); + if (TextUtils.isEmpty(cookie)) { + cookie = ""; + if (headers != null) { + for (Header header : headers) { + String key = header.getName(); + String value = header.getValue(); + if (key.contains("Set-Cookie")) + cookie += value + ";"; + } + if (cookie.length() > 0) { + cookie = cookie.substring(0, cookie.length() - 1); + } + } + } - public static void cleanCookie() { - appCookie = ""; + log("getCookie:" + cookie); + return cookie; } - public static String getCookie(AppContext appContext) { - if (appCookie == null || appCookie == "") { - appCookie = appContext.getProperty("cookie"); + private static void initSSL(AsyncHttpClient client) { + try { + /// We initialize a default Keystore + KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); + // We load the KeyStore + trustStore.load(null, null); + // We initialize a new SSLSocketFacrory + MySSLSocketFactory socketFactory = new MySSLSocketFactory(trustStore); + // We set that all host names are allowed in the socket factory + socketFactory.setHostnameVerifier(MySSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); + // We set the SSL Factory + client.setSSLSocketFactory(socketFactory); + // We initialize a GET http request + } catch (Exception e) { + e.printStackTrace(); + } + } + + @SuppressWarnings("deprecation") + private static class MySSLSocketFactory extends SSLSocketFactory { + SSLContext sslContext = SSLContext.getInstance("TLS"); + + @SuppressWarnings("WeakerAccess") + public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { + super(truststore); + + TrustManager tm = new X509TrustManager() { + @SuppressLint("TrustAllX509TrustManager") + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { + } + + @SuppressLint("TrustAllX509TrustManager") + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { + } + + public X509Certificate[] getAcceptedIssuers() { + return null; + } + }; + + sslContext.init(null, new TrustManager[]{tm}, null); + } + + @Override + public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException { + return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); + } + + @Override + public Socket createSocket() throws IOException { + return sslContext.getSocketFactory().createSocket(); } - return appCookie; } } diff --git a/app/src/main/java/net/oschina/app/api/ApiResponse.java b/app/src/main/java/net/oschina/app/api/ApiResponse.java deleted file mode 100644 index 119d9af584fa5d1a703fee3af0bb831b56ab6217..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/api/ApiResponse.java +++ /dev/null @@ -1,90 +0,0 @@ -package net.oschina.app.api; - -import org.json.JSONObject; - -public class ApiResponse { - protected Object _data; - protected String _message; - protected int _errorCode; - protected boolean _isOk; - private long _total; - private String _serverTime; - private boolean isCanceled; - - public ApiResponse(JSONObject json) { - if (json != null) { - setData(json.optJSONObject("data") == null ? json - .optJSONArray("data") : json.optJSONObject("data")); - setMessage(json.optString("result_desc")); - setErrorCode(json.optInt("result_code")); - setOk(getErrorCode() == 0); - setServerTime(json.optString("timestamp")); - } - } - - public Object getData() { - return _data; - } - - public void setData(Object _data) { - this._data = _data; - } - - public boolean isOk() { - return _isOk; - } - - public void setOk(boolean _isOk) { - this._isOk = _isOk; - } - - public String getMessage() { - return _message; - } - - public void setMessage(String _message) { - this._message = _message; - } - - public int getErrorCode() { - return _errorCode; - } - - public void setErrorCode(int _errorCode) { - this._errorCode = _errorCode; - } - - @Override - public String toString() { - return "data:" + getData() + " message:" + getMessage() + " errocode:" - + _errorCode; - } - - public void update(ApiResponse response) { - _message = response.getMessage(); - } - - public void setTotal(long total) { - _total = total; - } - - public long getTotal() { - return _total; - } - - public String getServerTime() { - return _serverTime; - } - - public void setServerTime(String _serverTime) { - this._serverTime = _serverTime; - } - - public boolean isCanceled() { - return isCanceled; - } - - public void setCanceled(boolean isCanceled) { - this.isCanceled = isCanceled; - } -} diff --git a/app/src/main/java/net/oschina/app/api/remote/OSChinaApi.java b/app/src/main/java/net/oschina/app/api/remote/OSChinaApi.java index cc5097959e8b65cb2ab05b106b1c4143db18d645..333916786727b64215f28a3648b1a87ae3c4c7e3 100644 --- a/app/src/main/java/net/oschina/app/api/remote/OSChinaApi.java +++ b/app/src/main/java/net/oschina/app/api/remote/OSChinaApi.java @@ -1,93 +1,89 @@ package net.oschina.app.api.remote; +import android.content.Context; import android.text.TextUtils; import com.loopj.android.http.AsyncHttpResponseHandler; import com.loopj.android.http.RequestParams; +import com.loopj.android.http.TextHttpResponseHandler; import net.oschina.app.AppContext; -import net.oschina.app.AppException; import net.oschina.app.api.ApiHttpClient; import net.oschina.app.bean.EventApplyData; -import net.oschina.app.bean.NewsList; import net.oschina.app.bean.Report; -import net.oschina.app.bean.Tweet; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.bean.SignUpEventOptions; +import net.oschina.app.improve.bean.simple.About; +import net.oschina.app.improve.detail.sign.StringParams; import net.oschina.app.team.bean.Team; import net.oschina.app.util.StringUtils; -import net.oschina.app.util.TLog; import org.kymjs.kjframe.utils.KJLoger; import java.io.File; import java.io.FileNotFoundException; -import java.net.URLEncoder; +import java.util.List; +import java.util.Map; +import static net.oschina.app.api.ApiHttpClient.post; + +/** + * OSChina Api v1 and v2 + */ public class OSChinaApi { - /** - * 登陆 - * - * @param username - * @param password - * @param handler - */ - public static void login(String username, String password, - AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams(); - params.put("username", username); - params.put("pwd", password); - params.put("keep_login", 1); - String loginurl = "action/api/login_validate"; - ApiHttpClient.post(loginurl, params, handler); - } + public static final int CATALOG_ALL = 0; + public static final int CATALOG_SOFTWARE = 1; + public static final int CATALOG_QUESTION = 2; + public static final int CATALOG_BLOG = 3; + public static final int CATALOG_TRANSLATION = 4; + public static final int CATALOG_EVENT = 5; + public static final int CATALOG_NEWS = 6; + public static final int CATALOG_TWEET = 100; - public static void openIdLogin(String s) { + public static final int COMMENT_SOFT = 1; // 软件推荐-不支持(默认软件评论其实是动弹) + public static final int COMMENT_QUESTION = 2; // 讨论区帖子 + public static final int COMMENT_BLOG = 3; // 博客 + public static final int COMMENT_TRANSLATION = 4; // 翻译文章 + public static final int COMMENT_EVENT = 5; // 活动类型 + public static final int COMMENT_NEWS = 6; // 资讯类型 + public static final int COMMENT_TWEET = 100; // 动弹 - } + public static final int COMMENT_HOT_ORDER = 2; //热门评论顺序 + public static final int COMMENT_NEW_ORDER = 1; //最新评论顺序 - /** - * 获取新闻列表 - * - * @param catalog - * 类别 (1,2,3) - * @param page - * 第几页 - * @param handler - */ - public static void getNewsList(int catalog, int page, - AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams(); - params.put("catalog", catalog); - params.put("pageIndex", page); - params.put("pageSize", AppContext.PAGE_SIZE); - if (catalog == NewsList.CATALOG_WEEK) { - params.put("show", "week"); - } else if (catalog == NewsList.CATALOG_MONTH) { - params.put("show", "month"); - } - ApiHttpClient.get("action/api/news_list", params, handler); - } + public static final int CATALOG_BANNER_NEWS = 1; // 资讯Banner + public static final int CATALOG_BANNER_BLOG = 2; // 博客Banner + public static final int CATALOG_BANNER_EVENT = 3; // 活动Banner - public static void getBlogList(String type, int pageIndex, - AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams(); - params.put("type", type); - params.put("pageIndex", pageIndex); - params.put("pageSize", AppContext.PAGE_SIZE); - ApiHttpClient.get("action/api/blog_list", params, handler); - } + public static final int CATALOG_BLOG_NORMAL = 1; // 最新 + public static final int CATALOG_BLOG_HEAT = 2; // 最热 + public static final int CATALOG_BLOG_RECOMMEND = 3; //推荐 - public static void getPostList(int catalog, int page, - AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams(); - params.put("catalog", catalog); - params.put("pageIndex", page); - params.put("pageSize", AppContext.PAGE_SIZE); - ApiHttpClient.get("action/api/post_list", params, handler); - } + public static final String CATALOG_NEWS_DETAIL = "news"; + public static final String CATALOG_TRANSLATE_DETAIL = "translation"; + public static final String CATALOG_SOFTWARE_DETAIL = "software"; + + public static final String LOGIN_WEIBO = "weibo"; + public static final String LOGIN_QQ = "qq"; + public static final String LOGIN_WECHAT = "wechat"; - public static void getPostListByTag(String tag, int page, - AsyncHttpResponseHandler handler) { + public static final int REGISTER_INTENT = 1; + public static final int RESET_PWD_INTENT = 2; + + + /* ============================================================================================= + * ============================================================================================= + * + * Oschina Api V1 + * Don't use them any more + * + * ============================================================================================= + * ============================================================================================= + */ + + @Deprecated + public static void getPostListByTag(String tag, int page, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("tag", tag); params.put("pageIndex", page); @@ -95,8 +91,8 @@ public class OSChinaApi { ApiHttpClient.get("action/api/post_list", params, handler); } - public static void getTweetList(int uid, int page, - AsyncHttpResponseHandler handler) { + @Deprecated + public static void getTweetList(int uid, int page, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); params.put("pageIndex", page); @@ -104,8 +100,8 @@ public class OSChinaApi { ApiHttpClient.get("action/api/tweet_list", params, handler); } - public static void getTweetTopicList(int page, String topic, - AsyncHttpResponseHandler handler) { + @Deprecated + public static void getTweetTopicList(int page, String topic, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("pageIndex", page); params.put("title", topic); @@ -113,66 +109,31 @@ public class OSChinaApi { ApiHttpClient.get("action/api/tweet_topic_list", params, handler); } - public static void getTweetLikeList(AsyncHttpResponseHandler handler) { - ApiHttpClient.get("action/api/my_tweet_like_list", handler); - } - - public static void pubLikeTweet(int tweetId, int authorId, - AsyncHttpResponseHandler handler) { - + @Deprecated + public static void pubLikeTweet(int tweetId, int authorId, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("tweetid", tweetId); - params.put("uid", AppContext.getInstance().getLoginUid()); + params.put("uid", AccountHelper.getUserId()); params.put("ownerOfTweet", authorId); - ApiHttpClient.post("action/api/tweet_like", params, handler); + post("action/api/tweet_like", params, handler); } - public static void pubUnLikeTweet(int tweetId, int authorId, - AsyncHttpResponseHandler handler) { + @Deprecated + public static void pubUnLikeTweet(int tweetId, int authorId, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("tweetid", tweetId); - params.put("uid", AppContext.getInstance().getLoginUid()); + params.put("uid", AccountHelper.getUserId()); params.put("ownerOfTweet", authorId); - ApiHttpClient.post("action/api/tweet_unlike", params, handler); - } - - public static void getTweetLikeList(int tweetId, int page, - AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams(); - params.put("tweetid", tweetId); - params.put("pageIndex", page); - params.put("pageSize", AppContext.PAGE_SIZE); - ApiHttpClient.get("action/api/tweet_like_list", params, handler); - - } - - public static void getActiveList(int uid, int catalog, int page, - AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams(); - params.put("uid", uid); - params.put("catalog", catalog); - params.put("pageIndex", page); - params.put("pageSize", AppContext.PAGE_SIZE); - ApiHttpClient.get("action/api/active_list", params, handler); - } - - public static void getFriendList(int uid, int relation, int page, - AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams(); - params.put("uid", uid); - params.put("relation", relation); - params.put("pageIndex", page); - params.put("pageSize", AppContext.PAGE_SIZE); - ApiHttpClient.get("action/api/friends_list", params, handler); + post("action/api/tweet_unlike", params, handler); } /** * 获取所有关注好友列表 * - * @param uid - * 指定用户UID + * @param uid 指定用户UID * @param handler - * */ + */ + @Deprecated public static void getAllFriendsList(int uid, int relation, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); @@ -181,41 +142,21 @@ public class OSChinaApi { ApiHttpClient.get("action/api/friends_list", params, handler); } - /** - * 获取用户收藏 - * - * @param uid - * 指定用户UID - * @param type - * 收藏类型: 0:全部收藏 1:软件 2:话题 3:博客 4:新闻 5:代码 - * @param page - * @param handler - */ - public static void getFavoriteList(int uid, int type, int page, - AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams(); - params.put("uid", uid); - params.put("type", type); - params.put("pageIndex", page); - params.put("pageSize", AppContext.PAGE_SIZE); - ApiHttpClient.get("action/api/favorite_list", params, handler); - } - /** * 分类列表 * - * @param tag - * 第一级:0 + * @param tag 第一级:0 * @param handler */ - public static void getSoftwareCatalogList(int tag, - AsyncHttpResponseHandler handler) { + @Deprecated + public static void getSoftwareCatalogList(int tag, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams("tag", tag); ApiHttpClient.get("action/api/softwarecatalog_list", params, handler); } + @Deprecated public static void getSoftwareTagList(int searchTag, int page, - AsyncHttpResponseHandler handler) { + AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("searchTag", searchTag); params.put("pageIndex", page); @@ -224,13 +165,13 @@ public class OSChinaApi { } /** - * @param searchTag - *   软件分类  推荐:recommend 最新:time 热门:view 国产:list_cn + * @param searchTag   软件分类  推荐:recommend 最新:time 热门:view 国产:list_cn * @param page * @param handler */ + @Deprecated public static void getSoftwareList(String searchTag, int page, - AsyncHttpResponseHandler handler) { + AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("searchTag", searchTag); params.put("pageIndex", page); @@ -243,12 +184,13 @@ public class OSChinaApi { * * @PARAM ID * @PARAM CATALOG - * 1新闻 2帖子 3动弹 4动态 + * 1新闻 2帖子 3动弹 4动态 * @PARAM PAGE * @PARAM HANDLER */ - public static void getCommentList(int id, int catalog, int page, - AsyncHttpResponseHandler handler) { + @Deprecated + public static void getCommentList(int id, int catalog, int page + , AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("catalog", catalog); params.put("id", id); @@ -258,8 +200,8 @@ public class OSChinaApi { ApiHttpClient.get("action/api/comment_list", params, handler); } - public static void getBlogCommentList(int id, int page, - AsyncHttpResponseHandler handler) { + @Deprecated + public static void getBlogCommentList(int id, int page, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("id", id); params.put("pageIndex", page); @@ -267,132 +209,31 @@ public class OSChinaApi { ApiHttpClient.get("action/api/blogcomment_list", params, handler); } - public static void getChatMessageList(int friendId, int page, AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams(); - params.put("id", friendId); - params.put("pageIndex", page); - params.put("pageSize", AppContext.PAGE_SIZE); - ApiHttpClient.get("action/api/message_detail", params, handler); - } - - public static void getUserInformation(int uid, int hisuid, String hisname, - int pageIndex, AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams(); - params.put("uid", uid); - params.put("hisuid", hisuid); - params.put("hisname", hisname); - params.put("pageIndex", pageIndex); - params.put("pageSize", AppContext.PAGE_SIZE); - ApiHttpClient.get("action/api/user_information", params, handler); - } - - @SuppressWarnings("deprecation") - public static void getUserBlogList(int authoruid, final String authorname, - final int uid, final int pageIndex, AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams(); - params.put("authoruid", authoruid); - params.put("authorname", URLEncoder.encode(authorname)); - params.put("uid", uid); - params.put("pageIndex", pageIndex); - params.put("pageSize", AppContext.PAGE_SIZE); - ApiHttpClient.get("action/api/userblog_list", params, handler); - } - - public static void updateRelation(int uid, int hisuid, int newrelation, - AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams(); - params.put("uid", uid); - params.put("hisuid", hisuid); - params.put("newrelation", newrelation); - ApiHttpClient.post("action/api/user_updaterelation", params, handler); - } - - public static void getMyInformation(int uid, - AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams(); - params.put("uid", uid); - ApiHttpClient.get("action/api/my_information", params, handler); - } - - /** - * 获取新闻明细 - * - * @param id 新闻的id - * @param handler - */ - public static void getNewsDetail(int id, AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams("id", id); - ApiHttpClient.get("action/api/news_detail", params, handler); - } - - public static void getBlogDetail(int id, AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams("id", id); - ApiHttpClient.get("action/api/blog_detail", params, handler); - } - - /** - * 获取软件详情 - * - * @param ident - * @param handler - */ - public static void getSoftwareDetail(String ident, - AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams("ident", - ident); - ApiHttpClient.get("action/api/software_detail", params, handler); - } - - /*** - * 通过id获取软件详情 - * @param id - * @param handler - */ - public static void getSoftwareDetail(int id, AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams("id", - id); - ApiHttpClient.get("action/api/software_detail", params, handler); - } - - public static void getPostDetail(int id, AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams("id", id); - ApiHttpClient.get("action/api/post_detail", params, handler); - } - - public static void getTweetDetail(int id, AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams("id", id); - ApiHttpClient.get("action/api/tweet_detail", params, handler); - } - /** * 用户针对某个新闻,帖子,动弹,消息发表评论的接口,参数使用POST方式提交 * - * @param catalog - *    1新闻  2 帖子  3 动弹  4消息中心 - * @param id - * 被评论的某条新闻,帖子,动弹或者某条消息的id - * @param uid - * 当天登陆用户的UID - * @param content - * 发表的评论内容 - * @param isPostToMyZone - * 是否转发到我的空间,0不转发  1转发到我的空间(注意该功能之对某条动弹进行评论是有效,其他情况下服务器借口可以忽略该参数) + * @param catalog    1新闻  2 帖子  3 动弹  4消息中心 + * @param id 被评论的某条新闻,帖子,动弹或者某条消息的id + * @param uid 当天登陆用户的UID + * @param content 发表的评论内容 + * @param isPostToMyZone 是否转发到我的空间,0不转发  1转发到我的空间(注意该功能之对某条动弹进行评论是有效,其他情况下服务器借口可以忽略该参数) * @param handler */ - public static void publicComment(int catalog, int id, int uid, - String content, int isPostToMyZone, AsyncHttpResponseHandler handler) { + @Deprecated + public static void publicComment(int catalog, long id, int uid, String content + , int isPostToMyZone, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("catalog", catalog); params.put("id", id); params.put("uid", uid); params.put("content", content); params.put("isPostToMyZone", isPostToMyZone); - ApiHttpClient.post("action/api/comment_pub", params, handler); + post("action/api/comment_pub", params, handler); } - public static void replyComment(int id, int catalog, int replyid, - int authorid, int uid, String content, - AsyncHttpResponseHandler handler) { + @Deprecated + public static void replyComment(int id, int catalog, int replyid, int authorid + , int uid, String content, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("catalog", catalog); params.put("id", id); @@ -400,250 +241,104 @@ public class OSChinaApi { params.put("content", content); params.put("replyid", replyid); params.put("authorid", authorid); - ApiHttpClient.post("action/api/comment_reply", params, handler); + post("action/api/comment_reply", params, handler); } - public static void publicBlogComment(int blog, int uid, String content, - AsyncHttpResponseHandler handler) { + @Deprecated + public static void publicBlogComment(long blog, int uid, String content + , AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("blog", blog); params.put("uid", uid); params.put("content", content); - ApiHttpClient.post("action/api/blogcomment_pub", params, handler); + post("action/api/blogcomment_pub", params, handler); } - public static void replyBlogComment(int blog, int uid, String content, - int reply_id, int objuid, AsyncHttpResponseHandler handler) { + @Deprecated + public static void replyBlogComment(long blog, long uid, String content, long reply_id + , long objuid, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("blog", blog); params.put("uid", uid); params.put("content", content); params.put("reply_id", reply_id); params.put("objuid", objuid); - ApiHttpClient.post("action/api/blogcomment_pub", params, handler); + post("action/api/blogcomment_pub", params, handler); } - public static void pubTweet(Tweet tweet, AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams(); - params.put("uid", tweet.getAuthorid()); - params.put("msg", tweet.getBody()); - - // Map files = new HashMap(); - if (!TextUtils.isEmpty(tweet.getImageFilePath())) { - try { - params.put("img", new File(tweet.getImageFilePath())); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } - } - if (!TextUtils.isEmpty(tweet.getAudioPath())) { - try { - params.put("amr", new File(tweet.getAudioPath())); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } - } - ApiHttpClient.post("action/api/tweet_pub", params, handler); - } - - public static void pubSoftWareTweet(Tweet tweet, int softid, - AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams(); - params.put("uid", tweet.getAuthorid()); - params.put("msg", tweet.getBody()); - params.put("project", softid); - ApiHttpClient.post("action/api/software_tweet_pub", params, handler); - } - - public static void deleteTweet(int uid, int tweetid, - AsyncHttpResponseHandler handler) { + @Deprecated + public static void deleteTweet(int uid, int tweetid, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); params.put("tweetid", tweetid); - ApiHttpClient.post("action/api/tweet_delete", params, handler); + post("action/api/tweet_delete", params, handler); } + @Deprecated public static void deleteComment(int id, int catalog, int replyid, - int authorid, AsyncHttpResponseHandler handler) { + int authorid, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("id", id); params.put("catalog", catalog); params.put("replyid", replyid); params.put("authorid", authorid); - ApiHttpClient.post("action/api/comment_delete", params, handler); - } - - public static void deleteBlog(int uid, int authoruid, int id, - AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams(); - params.put("uid", uid); - params.put("authoruid", authoruid); - params.put("id", id); - ApiHttpClient.post("action/api/userblog_delete", params, handler); + post("action/api/comment_delete", params, handler); } - public static void deleteBlogComment(int uid, int blogid, int replyid, - int authorid, int owneruid, AsyncHttpResponseHandler handler) { + @Deprecated + public static void deleteBlogComment(int uid, int blogid, int replyid, int authorid + , int owneruid, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); params.put("blogid", blogid); params.put("replyid", replyid); params.put("authorid", authorid); params.put("owneruid", owneruid); - ApiHttpClient.post("action/api/blogcomment_delete", params, handler); + post("action/api/blogcomment_delete", params, handler); } /** * 用户添加收藏 * - * @param uid - * 用户UID - * @param objid - * 比如是新闻ID 或者问答ID 或者动弹ID - * @param type - * 1:软件 2:话题 3:博客 4:新闻 5:代码 + * @param uid 用户UID + * @param objid 比如是新闻ID 或者问答ID 或者动弹ID + * @param type 1:软件 2:话题 3:博客 4:新闻 5:代码 */ - public static void addFavorite(int uid, int objid, int type, - AsyncHttpResponseHandler handler) { + @Deprecated + public static void addFavorite(int uid, long objid, int type, + AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); params.put("objid", objid); params.put("type", type); - ApiHttpClient.post("action/api/favorite_add", params, handler); + post("action/api/favorite_add", params, handler); } - public static void delFavorite(int uid, int objid, int type, - AsyncHttpResponseHandler handler) { + @Deprecated + public static void delFavorite(int uid, long objid, int type, + AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); params.put("objid", objid); params.put("type", type); - ApiHttpClient.post("action/api/favorite_delete", params, handler); - } - - public static void getSearchList(String catalog, String content, - int pageIndex, AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams(); - params.put("catalog", catalog); - params.put("content", content); - params.put("pageIndex", pageIndex); - params.put("pageSize", AppContext.PAGE_SIZE); - ApiHttpClient.get("action/api/search_list", params, handler); - } - - public static void publicMessage(int uid, int receiver, String content, - AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams(); - params.put("uid", uid); - params.put("receiver", receiver); - params.put("content", content); - - ApiHttpClient.post("action/api/message_pub", params, handler); - } - - public static void deleteMessage(int uid, int friendid, - AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams(); - params.put("uid", uid); - params.put("friendid", friendid); - ApiHttpClient.post("action/api/message_delete", params, handler); - } - - public static void forwardMessage(int uid, String receiverName, - String content, AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams(); - params.put("uid", uid); - params.put("receiverName", receiverName); - params.put("content", content); - ApiHttpClient.post("action/api/message_pub", params, handler); - } - - public static void getMessageList(int uid, int pageIndex, - AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams(); - params.put("uid", uid); - params.put("pageIndex", pageIndex); - params.put("pageSize", AppContext.PAGE_SIZE); - ApiHttpClient.get("action/api/message_list", params, handler); - } - - public static void updatePortrait(int uid, File portrait, - AsyncHttpResponseHandler handler) throws FileNotFoundException { - RequestParams params = new RequestParams(); - params.put("uid", uid); - params.put("portrait", portrait); - ApiHttpClient.post("action/api/portrait_update", params, handler); - } - - public static void getNotices(AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams(); - params.put("uid", AppContext.getInstance().getLoginUid()); - ApiHttpClient.get("action/api/user_notice", params, handler); - } - - /** - * 清空通知消息 - * - * @param uid - * @param type - * 1:@我的信息 2:未读消息 3:评论个数 4:新粉丝个数 - * @return - * @throws AppException - */ - public static void clearNotice(int uid, int type, - AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams(); - params.put("uid", uid); - params.put("type", type); - ApiHttpClient.post("action/api/notice_clear", params, handler); + post("action/api/favorite_delete", params, handler); } - public static void singnIn(String url, AsyncHttpResponseHandler handler) { + @Deprecated + public static void signin(String url, AsyncHttpResponseHandler handler) { ApiHttpClient.getDirect(url, handler); } - /** - * 获取软件的动态列表 - * - * @param softid - * @param handler - */ - public static void getSoftTweetList(int softid, int page, - AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams(); - params.put("project", softid); - params.put("pageIndex", page); - params.put("pageSize", AppContext.PAGE_SIZE); - ApiHttpClient.get("action/api/software_tweet_list", params, handler); - } - - public static void checkUpdate(AsyncHttpResponseHandler handler) { - ApiHttpClient.get("MobileAppVersion.xml", handler); - } - - /** - * 查找用户 - * - * @param username - * @param handler - */ - public static void findUser(String username, - AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams(); - params.put("name", username); - ApiHttpClient.get("action/api/find_user", params, handler); - } - /** * 获取活动列表 - * + * * @param pageIndex - * @param uid - * <= 0 近期活动 实际的用户ID 则获取用户参与的活动列表,需要已登陆的用户 + * @param uid <= 0 近期活动 实际的用户ID 则获取用户参与的活动列表,需要已登陆的用户 * @param handler */ + @Deprecated public static void getEventList(int pageIndex, int uid, - AsyncHttpResponseHandler handler) { + AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("pageIndex", pageIndex); params.put("uid", uid); @@ -653,13 +348,14 @@ public class OSChinaApi { /** * 获取某活动已出席的人员列表 - * + * * @param eventId * @param pageIndex * @param handler */ + @Deprecated public static void getEventApplies(int eventId, int pageIndex, - AsyncHttpResponseHandler handler) { + AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("pageIndex", pageIndex); params.put("event_id", eventId); @@ -669,10 +365,11 @@ public class OSChinaApi { /** * 举报 - * + * * @param report * @param handler */ + @Deprecated public static void report(Report report, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("obj_id", report.getObjId()); @@ -683,37 +380,17 @@ public class OSChinaApi { && !StringUtils.isEmpty(report.getOtherReason())) { params.put("memo", report.getOtherReason()); } - ApiHttpClient.post("action/communityManage/report", params, handler); - } - - /** - * 摇一摇,随机数据 - * - * @param handler - */ - public static void shake(AsyncHttpResponseHandler handler) { - shake(-1, handler); - } - - /** - * 摇一摇指定请求类型 - */ - public static void shake(int type, AsyncHttpResponseHandler handler) { - String inter = "action/api/rock_rock"; - if (type > 0) { - inter = (inter + "/?type=" + type); - } - ApiHttpClient.get(inter, handler); + post("action/communityManage/report", params, handler); } /** * 活动报名 - * + * * @param data * @param handler */ - public static void eventApply(EventApplyData data, - AsyncHttpResponseHandler handler) { + @Deprecated + public static void eventApply(EventApplyData data, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("event", data.getEvent()); params.put("user", data.getUser()); @@ -725,47 +402,19 @@ public class OSChinaApi { if (!StringUtils.isEmpty(data.getRemark())) { params.put("misc_info", data.getRemark()); } - ApiHttpClient.post("action/api/event_apply", params, handler); - } - - private static void uploadLog(String data, String report, - AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams(); - params.put("app", "1"); - params.put("report", report); - params.put("msg", data); - ApiHttpClient.post("action/api/user_report_to_admin", params, handler); - } - - /** - * BUG上报 - * - * @param data - * @param handler - */ - public static void uploadLog(String data, AsyncHttpResponseHandler handler) { - uploadLog(data, "1", handler); - } - - /** - * 反馈意见 - * - * @param data - * @param handler - */ - public static void feedback(String data, AsyncHttpResponseHandler handler) { - uploadLog(data, "2", handler); + post("action/api/event_apply", params, handler); } /** * team动态 - * + * * @param team * @param page * @param handler */ + @Deprecated public static void teamDynamic(Team team, int page, - AsyncHttpResponseHandler handler) { + AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); // int uid = AppContext.getInstance().getLoginUid(); // params.put("uid", uid); @@ -778,47 +427,35 @@ public class OSChinaApi { /** * 获取team列表 - * + * * @param handler */ - public static void teamList(AsyncHttpResponseHandler handler) { + @Deprecated + public static void teamList(AsyncHttpResponseHandler handler, Context context) { RequestParams params = new RequestParams(); - params.put("uid", AppContext.getInstance().getLoginUid()); + params.put("uid", AccountHelper.getUserId()); ApiHttpClient.get("action/api/team_list", params, handler); } /** * 获取team成员列表 - * + * * @param handler */ + @Deprecated public static void getTeamMemberList(int teamid, - AsyncHttpResponseHandler handler) { + AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamid); ApiHttpClient.get("action/api/team_member_list", params, handler); } - /** - * 获取team成员个人信息 - * - * @param handler - */ - public static void getTeamUserInfo(String teamid, String uid, - int pageIndex, AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams(); - params.put("teamid", teamid); - params.put("uid", uid); - params.put("pageIndex", pageIndex); - params.put("pageSize", 20); - ApiHttpClient.get("action/api/team_user_information", params, handler); - } - /** * 获取我的任务中进行中、未完成、已完成等状态的数量 */ + @Deprecated public static void getMyIssueState(String teamid, String uid, - AsyncHttpResponseHandler handler) { + AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamid); params.put("uid", uid); @@ -829,8 +466,9 @@ public class OSChinaApi { /** * 获取指定用户的动态 */ + @Deprecated public static void getUserDynamic(int teamid, String uid, int pageIndex, - AsyncHttpResponseHandler handler) { + AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamid); params.put("pageIndex", pageIndex); @@ -842,14 +480,15 @@ public class OSChinaApi { /** * 动态详情 - * + * * @param activeid * @param teamid * @param uid * @param handler */ - public static void getDynamicDetail(int activeid, int teamid, int uid, - AsyncHttpResponseHandler handler) { + @Deprecated + public static void getDynamicDetail(int activeid, int teamid, int uid + , AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamid); params.put("uid", uid); @@ -861,7 +500,7 @@ public class OSChinaApi { * 获取指定用户的任务 */ public static void getMyIssue(String teamid, String uid, int pageIndex, - String type, AsyncHttpResponseHandler handler) { + String type, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamid); params.put("uid", uid); @@ -874,14 +513,15 @@ public class OSChinaApi { /** * 获取指定周周报 - * + * * @param teamid * @param year * @param week * @param handler */ - public static void getDiaryFromWhichWeek(int teamid, int year, int week, - AsyncHttpResponseHandler handler) { + @Deprecated + public static void getDiaryFromWhichWeek(int teamid, int year, int week + , AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamid); params.put("year", year); @@ -891,14 +531,12 @@ public class OSChinaApi { /** * 删除一个便签 - * - * @param id - * 便签id - * @param uid - * 用户id + * + * @param id 便签id + * @param uid 用户id */ - public static void deleteNoteBook(int id, int uid, - AsyncHttpResponseHandler handler) { + @Deprecated + public static void deleteNoteBook(int id, long uid, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); params.put("id", id); // 便签id @@ -906,21 +544,15 @@ public class OSChinaApi { .get("action/api/team_stickynote_recycle", params, handler); } - public static void getNoteBook(int uid, AsyncHttpResponseHandler handler) { - RequestParams params = new RequestParams(); - params.put("uid", uid); - ApiHttpClient.get("action/api/team_sticky_list", params, handler); - } - /** * 获取指定周报的详细信息 - * + * * @param teamid * @param diaryid * @param handler */ - public static void getDiaryDetail(int teamid, int diaryid, - AsyncHttpResponseHandler handler) { + @Deprecated + public static void getDiaryDetail(int teamid, int diaryid, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamid); params.put("diaryid", diaryid); @@ -929,13 +561,13 @@ public class OSChinaApi { /** * diary评论列表 - * + * * @param teamid * @param diaryid * @param handler */ - public static void getDiaryComment(int teamid, int diaryid, - AsyncHttpResponseHandler handler) { + @Deprecated + public static void getDiaryComment(int teamid, int diaryid, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamid); params.put("id", diaryid); @@ -943,87 +575,1030 @@ public class OSChinaApi { params.put("pageIndex", 0); params.put("pageSize", "20"); KJLoger.debug(teamid + "==getDiaryComment接口=" + diaryid); - ApiHttpClient - .get("action/api/team_reply_list_by_type", params, handler); + ApiHttpClient.get("action/api/team_reply_list_by_type", params, handler); + } + + /*** + * 客户端扫描二维码登陆 + * + * @param url + * @param handler + * @return void + * @author 火蚁 2015-3-13 上午11:45:47 + */ + @Deprecated + public static void scanQrCodeLogin(String url, AsyncHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + String uuid = url.substring(url.lastIndexOf("=") + 1); + params.put("uuid", uuid); + ApiHttpClient.getDirect(url, handler); } + + + + + /* ============================================================================================= + * ============================================================================================= + * + * Oschina Api V2 + * + * ============================================================================================= + * ============================================================================================= + */ + /** - * 周报评论(以后可改为全局评论) - * - * @param uid - * @param teamid - * @param diaryId - * @param content + * pub software tweet + * + * @param content content + * @param handler handler + */ + public static void pubSoftwareTweet(String content, AsyncHttpResponseHandler handler) { + if (!TextUtils.isEmpty(content)) { + RequestParams params = new RequestParams(); + params.put("content", content); + post("/action/apiv2/tweet", params, handler); + } + } + + /** + * del software tweet + * + * @param sourceId tweet's id + * @param handler handler + */ + public static void delSoftwareTweet(long sourceId, AsyncHttpResponseHandler handler) { + if (sourceId <= 0) return; + RequestParams params = new RequestParams(); + params.put("sourceId", sourceId); + post("/action/apiv2/tweet_delete", params, handler); + + } + + /** + * get software tweet list + * + * @param tag software tag + * @param handler handler + */ + public static void getSoftwareTweetList(String tag, String pageToken, TextHttpResponseHandler handler) { + if (TextUtils.isEmpty(tag)) return; + RequestParams params = new RequestParams(); + params.put("tag", tag); + params.put("pageToken", pageToken); + ApiHttpClient.get("action/apiv2/tweets", params, handler); + } + + /** + * pub tweet like status + * + * @param sourceId source id + * @param handler handler + */ + public static void pubSoftwareLike(long sourceId, TextHttpResponseHandler handler) { + if (sourceId <= 0) return; + RequestParams params = new RequestParams(); + params.put("sourceId", sourceId); + post("action/apiv2/tweet_like_reverse", params, handler); + } + + /** + * 请求资讯详情 + * + * @param id 请求该资讯详情页 + * @param handler AsyncHttpResponseHandler + */ + public static void getNewsDetail(long id, String type, AsyncHttpResponseHandler handler) { + if (id <= 0) return; + RequestParams params = new RequestParams(); + params.put("id", id); + ApiHttpClient.get("action/apiv2/" + type, params, handler); + } + + /** + * 请求资讯详情 [直接用软件名去请求] + * + * @param ident 请求该资讯详情页 + * @param handler AsyncHttpResponseHandler + */ + public static void getSoftwareDetail(String ident, String type, AsyncHttpResponseHandler handler) { + if (TextUtils.isEmpty(ident)) return; + RequestParams params = new RequestParams(); + params.put("ident", ident); + ApiHttpClient.get("action/apiv2/" + type, params, handler); + } + + /** + * 他人博客列表 + * + * @param pageToken page token + * @param uid user id + * @param uname user name + * @param handler handler + */ + public static void getSomeoneBlogs(String pageToken, long uid, String uname, + AsyncHttpResponseHandler handler) { + if (uid <= 0 && TextUtils.isEmpty(uname)) return; + RequestParams params = new RequestParams(); + params.put("pageToken", pageToken); + params.put("authorId", uid); + params.put("authorName", uname); + ApiHttpClient.get("action/apiv2/blog_list", params, handler); + } + + /** + * 请求用户自己的博客列表 + * + * @param pageToken 请求上下页数据令牌 + * @param handler AsyncHttpResponseHandler + */ + public static void getUserQuestionList(String pageToken, long userId, AsyncHttpResponseHandler handler) { + if (userId <= 0) return; + RequestParams params = new RequestParams(); + params.put("pageToken", pageToken); + params.put("authorId", userId); + ApiHttpClient.get("action/apiv2/question", params, handler); + } + + + /** + * 请求博客详情 + * + * @param id 博客id + * @param handler AsyncHttpResponseHandler + */ + public static void getBlogDetail(long id, AsyncHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("id", id); + ApiHttpClient.get("action/apiv2/blog", params, handler); + } + + /** + * 请求活动详情 + * + * @param id id + * @param handler handler + */ + public static void getEventDetail(long id, AsyncHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("id", id); + ApiHttpClient.get("action/apiv2/event", params, handler); + } + + /** + * 更改收藏状态 + * + * @param id id + * @param type type + * @param handler handler + */ + public static void getFavReverse(long id, int type, AsyncHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("id", id); + params.put("type", type); + ApiHttpClient.get("action/apiv2/favorite_reverse", params, handler); + } + + /** + * 更改关注状态(关注/取消关注) + * + * @param id id + * @param handler handler + */ + public static void addUserRelationReverse(long id, AsyncHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("id", id); + ApiHttpClient.get("action/apiv2/user_relation_reverse", params, handler); + } + + /** + * 请求问答详情 + * + * @param id 问答id + * @param handler AsyncHttpResponseHandler + */ + public static void getQuestionDetail(long id, AsyncHttpResponseHandler handler) { + if (id <= 0) return; + RequestParams params = new RequestParams(); + params.put("id", id); + ApiHttpClient.get("action/apiv2/question", params, handler); + } + + /** + * 请求评论详情 + * + * @param id 评论Id + * @param handler AsyncHttpResponseHandler + */ + public static void getCommentDetail(long id, long aid, int type, TextHttpResponseHandler handler) { + if (id <= 0) return; + RequestParams params = new RequestParams(); + params.put("id", id); + params.put("authorId", aid); + params.put("type", type); + ApiHttpClient.get("action/apiv2/comment_detail", params, handler); + } + + /** + * 请求评论列表 + * + * @param sourceId 目标Id,该sourceId为资讯、博客、问答等文章的Id + * @param type 问答类型 {@link #COMMENT_SOFT, #COMMENT_QUESTION, #COMMENT_BLOG}, + * {@link #COMMENT_TRANSLATION, #COMMENT_EVENT, #COMMENT_NEWS} + * @param parts 请求的数据节点 parts="refer,reply" + * @param pageToken 请求上下页数据令牌 + * @param handler AsyncHttpResponseHandler + */ + @Deprecated + public static void getComments(long sourceId, int type, String parts, String pageToken, TextHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("sourceId", sourceId); + params.put("type", type); + params.put("parts", parts); + params.put("pageToken", pageToken); + ApiHttpClient.get("action/apiv2/comment", params, handler); + } + + + /** + * 请求评论列表(适用于所有的评论,但不包括软件评论列表,软件评论列表实际为动弹) + * + * @param sourceId sourceId 该sourceId为资讯、博客、问答等文章的Id + * @param type type 问答类型 {@link #COMMENT_SOFT, #COMMENT_QUESTION, #COMMENT_BLOG}, + * {@link #COMMENT_TRANSLATION, #COMMENT_EVENT, #COMMENT_NEWS} + * @param parts parts 请求的数据节点 parts="refer,reply" + * @param order order 请求的排序方式 1.最新 2.热门 + * @param pageToken pageToken 请求上下页数据令牌 + * @param handler handler + */ + public static void getComments(long sourceId, int type, String parts, int order, String pageToken, TextHttpResponseHandler handler) { + if (sourceId <= 0) return; + RequestParams params = new RequestParams(); + params.put("sourceId", sourceId); + params.put("type", type); + params.put("parts", parts); + params.put("order", order); + params.put("pageToken", pageToken); + ApiHttpClient.get("action/apiv2/comment_list", params, handler); + } + + /** + * 发表评论 + * + * @param sid 文章id + * @param referId 引用的评论的id + * @param replyId 回复的评论的id + * @param oid 引用、回复的发布者id + * @param type 文章类型 1:软件推荐, 2:问答帖子, 3:博客, 4:翻译文章, 5:活动, 6:资讯 + * @param content 内容 + * @param handler 你懂得 + */ + public static void publishComment(long sid, long referId, long replyId, long oid, + int type, String content, TextHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("sourceId", sid); + params.put("type", type); + params.put("content", content); + if (referId > 0) + params.put("referId", referId); + if (replyId > 0) + params.put("replyId", replyId); + if (oid > 0) + params.put("reAuthorId", oid); + post("action/apiv2/comment_push", params, handler); + } + + + /** + * 发表资讯评论 + * + * @see {{@link #publicComment(int, long, int, String, int, AsyncHttpResponseHandler)}} + */ + public static void pubNewsComment(long sid, long commentId, long commentAuthorId + , String comment, TextHttpResponseHandler handler) { + if (commentId == 0 || commentId == sid) { + commentId = 0; + commentAuthorId = 0; + } + publishComment(sid, 0, commentId, commentAuthorId, 6, comment, handler); + } + + /** + * 发表问答评论 + * + * @see {{@link #publicComment(int, long, int, String, int, AsyncHttpResponseHandler)}} + */ + public static void pubQuestionComment(long sid, long commentId, long commentAuthorId + , String comment, TextHttpResponseHandler handler) { + if (commentId == 0 || commentId == sid) { + commentId = 0; + commentAuthorId = 0; + } + publishComment(sid, 0, commentId, commentAuthorId, 2, comment, handler); + } + + + /** + * 发表翻译评论 + * + * @see {{@link #publicComment(int, long, int, String, int, AsyncHttpResponseHandler)}} + */ + public static void pubTranslateComment(long sid, long commentId, long commentAuthorId + , String comment, TextHttpResponseHandler handler) { + if (commentId == 0 || commentId == sid) { + commentId = 0; + commentAuthorId = 0; + } + publishComment(sid, 0, commentId, commentAuthorId, 4, comment, handler); + } + + /** + * 发布博客评论 + * + * @see {{@link #publicComment(int, long, int, String, int, AsyncHttpResponseHandler)}} + */ + public static void pubBlogComment(long sid, long commentId, long commentAuthorId + , String comment, TextHttpResponseHandler handler) { + if (commentId == 0 || commentId == sid) { + commentId = 0; + commentAuthorId = 0; + } + publishComment(sid, 0, commentId, commentAuthorId, 3, comment, handler); + } + + /** + * 发布活动评论 + * + * @param sid sourceId + * @param commentId commentId + * @param commentAuthorId commentAuthorId + * @param comment comment + * @param handler handler + */ + public static void pubEventComment(long sid, long commentId, long commentAuthorId + , String comment, TextHttpResponseHandler handler) { + if (commentId == 0 || commentId == sid) { + commentId = 0; + commentAuthorId = 0; + } + publishComment(sid, 0, commentId, commentAuthorId, 5, comment, handler); + } + + /** + * 对资讯,博客,翻译详情下的评论列表进行顶操作(ps:默认现在只能顶,不能取消) + * + * @param sourceType sourceType + * @param commentId commentId + * @param commentAuthorId commentAuthorId + * @param voteOpt voteOpt + * @param handler handler + */ + public static void voteComment(int sourceType, long commentId, long commentAuthorId + , int voteOpt, TextHttpResponseHandler handler) { + if (commentId <= 0) return; + RequestParams params = new RequestParams(); + params.put("sourceType", sourceType); + params.put("commentId", commentId); + params.put("commentAuthorId", commentAuthorId); + params.put("voteOpt", voteOpt); + post("action/apiv2/comment_vote_reverse", params, handler); + + } + + /** + * 问答的回答, 顶\踩 + * + * @param sid source id 问答的id + * @param cid 回答的id + * @param opt 操作类型 0:取消, 1:顶, 2:踩 * @param handler */ - public static void sendComment(int uid, int teamid, int diaryId, - String content, AsyncHttpResponseHandler handler) { + public static void questionVote(long sid, long cid, int opt, TextHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("sourceId", sid); + params.put("commentId", cid); + params.put("voteOpt", opt); + post("action/apiv2/question_vote", params, handler); + } + + /** + * 上传图片接口 + * http://doc.oschina.net/app_v2?t=105508 + * + * @param token 上传口令,单次口令最多上传9张图片。 + * @param imagePath 图片地址 + * @param handler 回调 + */ + public static void uploadImage(String token, String imagePath, AsyncHttpResponseHandler handler) { + if (TextUtils.isEmpty(imagePath)) + throw new NullPointerException("imagePath is not null."); + RequestParams params = new RequestParams(); + params.put("token", token); + try { + params.put("resource", new File(imagePath)); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + post("action/apiv2/resource_image", params, handler); + } + + /** + * 发布动弹 + * 链接 http://doc.oschina.net/app_v2?t=105522 + * + * @param content 内容 + * @param imagesToken 图片token + * @param audioToken 语音token + * @param share 相关分享节点,仅仅关注 {@link About.Share#id}, {@link About.Share#type}, + * {@link About.Share#fromTweetId} + * @param handler 回调 + */ + public static void pubTweet(String content, String imagesToken, String audioToken, About.Share share, AsyncHttpResponseHandler handler) { + if (TextUtils.isEmpty(content)) + throw new NullPointerException("content is not null."); RequestParams params = new RequestParams(); - params.put("uid", uid); - params.put("teamid", teamid); - params.put("type", "118"); - params.put("tweetid", diaryId); params.put("content", content); - ApiHttpClient.post("action/api/team_tweet_reply", params, handler); + params.put("images", imagesToken); + params.put("audio", audioToken); + if (About.check(share)) { + params.put("aboutId", share.id); + params.put("aboutType", share.type); + params.put("aboutFromTweetId", share.fromTweetId); + } + post("action/apiv2/tweet", params, handler); } - /*** - * 客户端扫描二维码登陆 - * - * @author 火蚁 2015-3-13 上午11:45:47 - * - * @return void - * @param url + /** + * 请求用户动弹列表 + * + * @param authorId 用户id + * @param pageToken pageToken + * @param handler 回调 + */ + public static void getUserTweetList(long authorId, String pageToken, TextHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("authorId", authorId); + params.put("pageToken", pageToken); + ApiHttpClient.get("action/apiv2/tweets", params, handler); + } + + /** + * 请求动弹详情 + * + * @param id 动弹id + * @param handler 回调 + */ + public static void getTweetDetail(long id, TextHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("id", id); + ApiHttpClient.get("action/apiv2/tweet", params, handler); + } + + /** + * 请求动弹评论列表 + * + * @param sourceId 动弹id + * @param handler 回调 + */ + public static void getTweetCommentList(long sourceId, String pageToken, TextHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("sourceId", sourceId); + params.put("pageToken", pageToken); + ApiHttpClient.get("action/apiv2/tweet_comments", params, handler); + } + + /** + * 请求动弹点赞列表 + * + * @param sourceId 动弹id + * @param handler 回调 + */ + public static void getTweetLikeList(long sourceId, String pageToken, TextHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("sourceId", sourceId); + params.put("pageToken", pageToken); + ApiHttpClient.get("action/apiv2/tweet_likes", params, handler); + } + + + /** + * 发表动弹评论列表 + * + * @param sourceId 动弹id + * @param content 内容 + * @param replyId 回复的用户id + * @param handler 回调 + */ + public static void pubTweetComment(long sourceId, String content, long replyId, AsyncHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("sourceId", sourceId); + params.put("content", content); + if (replyId > 0) params.put("replyId", replyId); + post("action/apiv2/tweet_comment", params, handler); + } + + /** + * 更改动弹点赞状态 + * + * @param sourceId 动弹id + * @param handler 回调 + */ + public static void reverseTweetLike(long sourceId, TextHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("sourceId", sourceId); + ApiHttpClient.get("action/apiv2/tweet_like_reverse", params, handler); + } + + /** + * 删除动弹评论 + * + * @param sourceId 动弹id + * @param commentId 评论id + * @param handler 回调 + */ + public static void deleteTweetComment(long sourceId, long commentId, TextHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("sourceId", sourceId); + params.put("commentId", commentId); + ApiHttpClient.get("action/apiv2/tweet_comment_delete", params, handler); + } + + /** + * 删除动弹评论 + * + * @param sourceId 动弹id + * @param handler 回调 + */ + public static void deleteTweet(long sourceId, TextHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("sourceId", sourceId); + ApiHttpClient.get("action/apiv2/tweet_delete", params, handler); + } + + /** + * 获取消息列表 + * + * @param authorId authorId 用户id,不加该参数时返回所有给我发送消息的列表 + * @param pageToken pageToken + * @param handler 回调 + */ + public static void getMessageList(long authorId, String pageToken, TextHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("authorId", authorId); + params.put("pageToken", pageToken); + ApiHttpClient.get("action/apiv2/messages", params, handler); + } + + /** + * 获取用户私信列表 + * + * @param pageToken pageToken + * @param handler 回调 + */ + public static void getUserMessageList(String pageToken, TextHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("pageToken", pageToken); + ApiHttpClient.get("action/apiv2/user_msg_letters", params, handler); + } + + /** + * 发送消息 + * + * @param authorId 接收者 + * @param content 发送内容 + * @param handler 回调 + */ + public static void pubMessage(long authorId, String content, TextHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("authorId", authorId); + params.put("content", content); + post("action/apiv2/messages_pub", params, handler); + } + + public static void pubMessage(long authorId, File content, TextHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("authorId", authorId); + try { + params.put("file", content); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + post("action/apiv2/messages_pub", params, handler); + } + + /** + * 添加反馈,私信接口 + * + * @param authorId + * @param content + * @param file * @param handler */ - public static void scanQrCodeLogin(String url, - AsyncHttpResponseHandler handler) { + public static void pubMessage(long authorId, String content, File file, TextHttpResponseHandler handler) { RequestParams params = new RequestParams(); - String uuid = url.substring(url.lastIndexOf("=") + 1); - params.put("uuid", uuid); - ApiHttpClient.getDirect(url, handler); + params.put("authorId", authorId); + params.put("content", content); + if (file != null && file.exists()) { + try { + params.put("file", file); + } catch (Exception e) { + e.printStackTrace(); + } + } + post("action/apiv2/messages_pub", params, handler); } - /*** - * 使用第三方登陆 - * @param catalog 类别 - * @param openIdInfo 第三方的info + /** + * 获取AT我的列表。 + * + * @param pageToken pageToken + * @param handler 回调 + */ + public static void getMsgMentionList(String pageToken, TextHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("pageToken", pageToken); + ApiHttpClient.get("action/apiv2/user_msg_mentions", params, handler); + } + + /** + * 评论我的列表 + * + * @param pageToken pageToken + * @param handler 回调 + */ + public static void getMsgCommentList(String pageToken, TextHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("pageToken", pageToken); + ApiHttpClient.get("action/apiv2/user_msg_comments", params, handler); + } + + /** + * 获取某用户的信息 + * + * @param uid user id + * @param nick unique personal suffix + */ + public static void getUserInfo(long uid, String nick, String suffix, TextHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + if (uid > 0) params.put("id", uid); + params.put("nickname", nick); + params.put("suffix", suffix); + ApiHttpClient.get("action/apiv2/user_info", params, handler); + } + + /** + * 获取某用户的动态(讨论)列表 + * + * @param uid user id + * @param pageToken page token + * @param handler async handler + */ + public static void getUserActives(long uid, String pageToken, TextHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("id", uid); + params.put("pageToken", pageToken); + ApiHttpClient.get("action/apiv2/user_activity", params, handler); + } + + /** + * 获取当前的新消息数量 + * + * @param handler TextHttpResponseHandler + */ + public static void getNotice(TextHttpResponseHandler handler) { + ApiHttpClient.get("action/apiv2/notice", handler); + } + + /** + * 获取个人信息 + */ + public static void getUserInfo(TextHttpResponseHandler handler) { + // RequestParams params = new RequestParams(); + // params.put("id", uid); + ApiHttpClient.get("action/apiv2/user_info", handler); + + } + + /** + * update the user icon + * + * @param file file * @param handler handler */ - public static void open_login(String catalog, String openIdInfo, AsyncHttpResponseHandler handler) { + public static void updateUserIcon(File file, TextHttpResponseHandler handler) { + if (file == null) return; + RequestParams params = new RequestParams(); + try { + params.put("portrait", file); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + post("action/apiv2/user_edit_portrait", params, handler); + + } + + public static final int TYPE_USER_FOLOWS = 1; + public static final int TYPE_USER_FANS = 2; + + /** + * @param type {@link #TYPE_USER_FOLOWS ,#TYPE_USER_FANS} + * @param userId userId + * @param pageToken pageToken + * @param handler handler + */ + public static void getUserFansOrFlows(int type, long userId, String pageToken, TextHttpResponseHandler handler) { + if (userId <= 0) return; + RequestParams params = new RequestParams(); + params.put("id", userId); + params.put("pageToken", pageToken); + + String uri = "user_follows"; + if (type == TYPE_USER_FANS) { + uri = "user_fans"; + } + ApiHttpClient.get("action/apiv2/" + uri, params, handler); + } + + /** + * get user favorites + * + * @param catalog catalog {@link #CATALOG_ALL,#CATALOG_SOFTWARE,#CATALOG_QUESTION, + * {@link #CATALOG_BLOG,#CATALOG_TRANSLATION ,#CATALOG_EVENT,#CATALOG_NEWS} + * @param pagetoken pagetoken + * @param handler handler + */ + public static void getUserFavorites(int catalog, String pagetoken, TextHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("catalog", catalog); - params.put("openid_info", openIdInfo); - ApiHttpClient.post("action/api/openid_login", params, handler); + params.put("pageToken", pagetoken); + ApiHttpClient.get("action/apiv2/favorites", params, handler); } - /*** - * 第三方登陆账号绑定 - * @param catalog 类别(QQ、wechat) - * @param openIdInfo 第三方info - * @param userName 用户名 - * @param pwd 密码 - * @param handler handler + /** + * 摇一摇(抽奖) + * + * @param timestamp 当前摇一摇的时间戳 + * @param appToken App唯一校验 + * @param signature 加密后的字符串 + * @param handler + */ + public static void getShakePresent(long timestamp, String appToken, String signature, TextHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("timestamp", timestamp); + params.put("appToken", appToken); + params.put("signature", signature); + post("action/apiv2/shake_present", params, handler); + } + + /** + * 摇一摇(综合) + * + * @param handler + */ + public static void getShakeNews(TextHttpResponseHandler handler) { + ApiHttpClient.get("action/apiv2/shake_news", handler); + } + + public static void reward(Map pairs, AsyncHttpResponseHandler handler) { + RequestParams params = new RequestParams(pairs); + post("action/apiv2/reward_order", params, handler); + } + + public static void checkUpdate(TextHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("appId", 1); + params.put("catalog", 1); + params.put("all", false); + ApiHttpClient.get("action/apiv2/product_version", params, handler); + } + + public static void getCollectionList(String pageToken, TextHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("catalog", 0); + params.put("pageToken", pageToken); + ApiHttpClient.get("action/apiv2/favorites", params, handler); + } + + /** + * @param catalog open catalog + * @param openInfo openInfo + * @param handler handler */ - public static void bind_openid(String catalog, String openIdInfo, String userName, String pwd, AsyncHttpResponseHandler handler) { + public static void openLogin(String catalog, String openInfo, TextHttpResponseHandler handler) { + if (TextUtils.isEmpty(openInfo)) return; RequestParams params = new RequestParams(); params.put("catalog", catalog); - params.put("openid_info", openIdInfo); - params.put("username", userName); - params.put("pwd", pwd); - ApiHttpClient.post("action/api/openid_bind", params, handler); + params.put("info", openInfo); + + post("action/apiv2/account_open_login", params, handler); } - /*** - * 使用第三方账号注册 - * @param catalog 类别(qq、wechat) - * @param openIdInfo 第三方info - * @param handler handler + /** + * 搜索 + * + * @param catalog 搜索类型 + * @param content 搜索内容 + * @param pageToken next page token + * @param handler handler */ - public static void openid_reg(String catalog, String openIdInfo, AsyncHttpResponseHandler handler) { + public static void search(int catalog, String content, String pageToken, TextHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("catalog", catalog); - params.put("openid_info", openIdInfo); - ApiHttpClient.post("action/api/openid_reg", params, handler); + params.put("content", content); + params.put("pageToken", pageToken); + ApiHttpClient.get("action/apiv2/search", params, handler); + } + + /** + * login account + * + * @param username username + * @param pwd pwd + * @param handler handler + */ + public static void login(String username, String pwd, TextHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("account", username); + params.put("password", pwd); + post("action/apiv2/account_login", params, handler); + } + + public static void sendSmsCode(String phone, int intent, TextHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("phone", phone); + params.put("intent", intent); + post("action/apiv2/phone_send_code", params, handler); + } + + + /** + * validate and get phone token + * + * @param phoneNumber phoneNumber + * @param smsCode smsCode + * @param handler handler + */ + public static void validateRegisterInfo(String phoneNumber, String smsCode, TextHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("phone", phoneNumber); + params.put("code", smsCode); + post("action/apiv2/phone_validate", params, handler); + } + + + /** + * register user info + * + * @param username username + * @param password pwd + * @param gender gender + * @param phoneToken token + * @param handler handler + */ + public static void register(String username, String password, int gender + , String phoneToken, TextHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("username", username); + params.put("password", password); + params.put("gender", gender); + params.put("phoneToken", phoneToken); + + post("action/apiv2/account_register", params, handler); + } + + /** + * reset pwd + * + * @param password password + * @param phoneToken token + * @param handler handler + */ + public static void resetPwd(String password, String phoneToken + , TextHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("password", password); + params.put("phoneToken", phoneToken); + + post("action/apiv2/account_password_forgot", params, handler); + } + + /** + * 获得首页数据 + * + * @param api 动态api + * @param pageToken pageToken + * @param handler handler + */ + + public static void getSubscription(String api, String pageToken, TextHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("pageToken", pageToken); + ApiHttpClient.getHttpClient().get(api, params, handler); + } + + /** + * 获得banner + * + * @param api 动态api + * @param handler handler + */ + public static void getBanner(String api, TextHttpResponseHandler handler) { + ApiHttpClient.getHttpClient().get(api, handler); + } + + /** + * 动弹列表 + * + * @param aid author id, 请求某人的动弹 + * @param tag 相关话题 + * @param type 1: 广场(所有动弹), 2:朋友圈(好友动弹) + * @param order 1: 最新, 2:最热 + * @param handler handler + */ + public static void getTweetList(Long aid, String tag, Integer type, Integer order + , String pageToken, TextHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + if (aid != null) { + params.put("authorId", aid); + } else if (!TextUtils.isEmpty(tag)) { + params.put("tag", tag); + } else { + params.put("type", type); + } + params.put("order", order); + params.put("pageToken", pageToken); + ApiHttpClient.get("action/apiv2/tweet_list", params, handler); + } + + /** + * 新版获得各种类型详情统一接口和Model + */ + public static void getDetail(int type, long id, TextHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("type", type); + params.put("id", id); + ApiHttpClient.get("action/apiv2/detail", params, handler); + } + + /** + * event signin + * + * @param sourceId sourceId + * @param phone phone + * @param handler handler + */ + public static void eventSignin(long sourceId, String phone, TextHttpResponseHandler handler) { + if (sourceId <= 0) return; + RequestParams params = new RequestParams(); + params.put("sourceId", sourceId); + if (!TextUtils.isEmpty(phone)) + params.put("phone", phone); + ApiHttpClient.post("action/apiv2/event_signin", params, handler); + } + + /** + * 新版获得活动报名参数 + */ + public static void getSignUpOptions(long sourceId, TextHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("sourceId", sourceId); + ApiHttpClient.get("action/apiv2/event_apply_preload", params, handler); + } + + /** + * 新版活动报名,动态参数 + */ + public static void signUpEvent(long sourceId, List options, TextHttpResponseHandler handler) { + StringParams params = new StringParams(); + params.putForm("sourceId", String.valueOf(sourceId)); + for (SignUpEventOptions option : options) { + params.putForm(option.getKey(), option.getValue()); + } + ApiHttpClient.get("action/apiv2/event_apply", params, handler); + } + + /** + * 获取用户自己的活动 + * + * @param authorId authorId + * @param authorName authorName + * @param pageToken pageToken + * @param handler handler + */ + public static void getUserEvent(long authorId, String authorName, String pageToken, TextHttpResponseHandler handler) { + if (authorId <= 0) return; + RequestParams params = new RequestParams(); + params.put("authorId", authorId); + params.put("authorName", authorName); + params.put("pageToken", pageToken); + ApiHttpClient.get("action/apiv2/event_list", params, handler); + + } + + public static void syncSignUserInfo(long sourceId, TextHttpResponseHandler handler) { + if (sourceId <= 0) return; + RequestParams params = new RequestParams(); + params.put("sourceId", sourceId); + ApiHttpClient.post("action/apiv2/event_apply_info", params, handler); } } diff --git a/app/src/main/java/net/oschina/app/api/remote/OSChinaTeamApi.java b/app/src/main/java/net/oschina/app/api/remote/OSChinaTeamApi.java index 584b19d7746fa260450acdbe96a3300a5b25ac61..eeb9bc533485dfe5665e2bccf3fe652c52631c1b 100644 --- a/app/src/main/java/net/oschina/app/api/remote/OSChinaTeamApi.java +++ b/app/src/main/java/net/oschina/app/api/remote/OSChinaTeamApi.java @@ -1,34 +1,36 @@ package net.oschina.app.api.remote; -import java.io.File; -import java.io.FileNotFoundException; +import android.content.Context; +import android.text.TextUtils; + +import com.loopj.android.http.AsyncHttpResponseHandler; +import com.loopj.android.http.RequestParams; import net.oschina.app.AppContext; import net.oschina.app.api.ApiHttpClient; +import net.oschina.app.improve.account.AccountHelper; import net.oschina.app.team.bean.TeamIssue; import net.oschina.app.team.bean.TeamProject; -import android.text.TextUtils; -import com.loopj.android.http.AsyncHttpResponseHandler; -import com.loopj.android.http.RequestParams; +import java.io.File; +import java.io.FileNotFoundException; /** * osc team api集合类 - * + * * @author FireAnt(http://my.oschina.net/LittleDY) * @version 创建时间:2015年1月14日 下午3:32:18 - * */ public class OSChinaTeamApi { /** * 获取团队项目列表 - * + * * @param teamId * @param handler */ public static void getTeamProjectList(int teamId, - AsyncHttpResponseHandler handler) { + AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamId); ApiHttpClient.get("action/api/team_project_list", params, handler); @@ -36,14 +38,14 @@ public class OSChinaTeamApi { /** * 获取team动态列表 - * + * * @param teamId * @param activeId * @param pageIndex * @param handler */ public static void getTeamCommentList(int teamId, int activeId, - int pageIndex, AsyncHttpResponseHandler handler) { + int pageIndex, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamId); params.put("id", activeId); @@ -55,19 +57,18 @@ public class OSChinaTeamApi { /*** * 获取团队绑定项目的成员列表(包括管理员以及开发者) - * - * @author 火蚁 2015-2-5 下午6:45:41 - * - * @return void + * * @param teamId * @param teamProject * @param handler + * @return void + * @author 火蚁 2015-2-5 下午6:45:41 */ public static void getTeamProjectMemberList(int teamId, - TeamProject teamProject, AsyncHttpResponseHandler handler) { + TeamProject teamProject, AsyncHttpResponseHandler handler, Context context) { RequestParams params = new RequestParams(); params.put("teamid", teamId); - params.put("uid", AppContext.getInstance().getLoginUid()); + params.put("uid", AccountHelper.getUserId()); params.put("projectid", teamProject.getGit().getId()); String source = teamProject.getSource(); if (source != null && !TextUtils.isEmpty(source)) { @@ -80,20 +81,18 @@ public class OSChinaTeamApi { /*** * 获取项目的动态列表 - * - * @author 火蚁 2015-3-2 下午5:18:54 - * - * @return void + * * @param teamId * @param project - * @param type - * "all"(default),"issue","code","other" + * @param type "all"(default),"issue","code","other" * @param page * @param handler + * @return void + * @author 火蚁 2015-3-2 下午5:18:54 */ public static void getTeamProjectActiveList(int teamId, - TeamProject project, String type, int page, - AsyncHttpResponseHandler handler) { + TeamProject project, String type, int page, + AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamId); params.put("projectid", project.getGit().getId()); @@ -108,18 +107,14 @@ public class OSChinaTeamApi { /** * 获取某项目的任务列表 - * - * @param uId - * 用户id - * @param teamId - * 团队id - * @param projectId - * 项目id(当<=0或不设置时,查询非项目的任务列表) - * @param source - * "Git@OSC","GitHub"(只有设置了projectid值,这里才需要设置该值) + * + * @param uId 用户id + * @param teamId 团队id + * @param projectId 项目id(当<=0或不设置时,查询非项目的任务列表) + * @param source "Git@OSC","GitHub"(只有设置了projectid值,这里才需要设置该值) */ public static void getTeamCatalogIssueList(int uId, int teamId, - int projectId, String source, AsyncHttpResponseHandler handler) { + int projectId, String source, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uId); params.put("teamid", teamId); @@ -131,28 +126,22 @@ public class OSChinaTeamApi { /** * 获取指定任务列表的任务列表 - * + * * @param teamId - * @param projectId - * 项目id(-1获取非项目任务列表, 0获取所有任务列表) - * @param catalogId - * 任务列表的的目录id - * @param source - * "Team@OSC"(default),"Git@OSC","GitHub",如果指定了projectid的值, - * 这个值就是必须的 - * @param uid - * 如果指定该值,则获取该id用户相关的任务 - * @param state - * "all"(default),"opened","closed","outdate" - * @param scope - * "tome"(default,指派给我的任务),"meto"(我指派的任务) + * @param projectId 项目id(-1获取非项目任务列表, 0获取所有任务列表) + * @param catalogId 任务列表的的目录id + * @param source "Team@OSC"(default),"Git@OSC","GitHub",如果指定了projectid的值, + * 这个值就是必须的 + * @param uid 如果指定该值,则获取该id用户相关的任务 + * @param state "all"(default),"opened","closed","outdate" + * @param scope "tome"(default,指派给我的任务),"meto"(我指派的任务) * @param pageIndex * @param pageSize * @param handler */ public static void getTeamIssueList(int teamId, int projectId, - int catalogId, String source, int uid, String state, String scope, - int pageIndex, int pageSize, AsyncHttpResponseHandler handler) { + int catalogId, String source, int uid, String state, String scope, + int pageIndex, int pageSize, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamId); params.put("projectid", projectId); @@ -168,22 +157,20 @@ public class OSChinaTeamApi { /*** * 改变一个任务的状态 - * - * @author 火蚁 2015-3-6 上午11:44:01 - * - * @return void + * * @param teamId * @param issue - * @param target - * 修改的属性("state" : 状态, "assignee" 指派人, "deadline" : 截止日期) + * @param target 修改的属性("state" : 状态, "assignee" 指派人, "deadline" : 截止日期) * @param handler + * @return void + * @author 火蚁 2015-3-6 上午11:44:01 */ public static void changeIssueState(int teamId, TeamIssue issue, - String target, AsyncHttpResponseHandler handler) { + String target, AsyncHttpResponseHandler handler, Context context) { if (issue == null) return; RequestParams params = new RequestParams(); - params.put("uid", AppContext.getInstance().getLoginUid()); + params.put("uid", AccountHelper.getUserId()); params.put("teamid", teamId); params.put("target", target); params.put("issueid", issue.getId()); @@ -198,13 +185,13 @@ public class OSChinaTeamApi { } public static void pubTeamNewIssue(RequestParams params, - AsyncHttpResponseHandler handler) { + AsyncHttpResponseHandler handler) { ApiHttpClient.post("action/api/team_issue_pub", params, handler); } /*** * 获取团队的讨论区列表 - * + * * @param type * @param teamId * @param uid @@ -212,7 +199,7 @@ public class OSChinaTeamApi { * @param handler */ public static void getTeamDiscussList(String type, int teamId, int uid, - int pageIndex, AsyncHttpResponseHandler handler) { + int pageIndex, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("type", type); params.put("teamid", teamId); @@ -224,16 +211,15 @@ public class OSChinaTeamApi { /*** * 获取讨论贴详情 - * - * @author 火蚁 2015-2-2 下午6:19:54 - * - * @return void + * * @param teamId * @param discussId * @param handler + * @return void + * @author 火蚁 2015-2-2 下午6:19:54 */ public static void getTeamDiscussDetail(int teamId, int discussId, - AsyncHttpResponseHandler handler) { + AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamId); params.put("discussid", discussId); @@ -242,18 +228,17 @@ public class OSChinaTeamApi { /*** * 发表讨论贴评论 - * - * @author 火蚁 2015-2-3 下午2:42:54 - * - * @return void + * * @param uid * @param teamId - * @param dicussId + * @param discussId * @param content * @param handler + * @return void + * @author 火蚁 2015-2-3 下午2:42:54 */ public static void pubTeamDiscussReply(int uid, int teamId, int discussId, - String content, AsyncHttpResponseHandler handler) { + String content, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); params.put("teamid", teamId); @@ -264,21 +249,19 @@ public class OSChinaTeamApi { /*** * 发表一条综合评论 动态、分享内容、周报 - * - * @author 火蚁 2015-3-6 下午3:31:07 - * - * @return void + * * @param teamId - * @param type - * 普通动态-110,分享内容-114, 周报-118 + * @param type 普通动态-110,分享内容-114, 周报-118 * @param tweetId * @param content * @param handler + * @return void + * @author 火蚁 2015-3-6 下午3:31:07 */ public static void pubTeamTweetReply(int teamId, int type, long tweetId, - String content, AsyncHttpResponseHandler handler) { + String content, AsyncHttpResponseHandler handler, Context context) { RequestParams params = new RequestParams(); - params.put("uid", AppContext.getInstance().getLoginUid()); + params.put("uid", AccountHelper.getUserId()); params.put("type", type); params.put("teamid", teamId); params.put("tweetid", tweetId); @@ -288,12 +271,11 @@ public class OSChinaTeamApi { /*** * 获取团队任务详情 - * + * * @author 火蚁 2015-1-27 下午7:47:17 - * */ public static void getTeamIssueDetail(int teamId, int issueId, - AsyncHttpResponseHandler handler) { + AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamId); params.put("issueid", issueId); @@ -302,7 +284,7 @@ public class OSChinaTeamApi { /*** * 获取团队的周报列表 - * + * * @param uid * @param teamId * @param year @@ -311,7 +293,7 @@ public class OSChinaTeamApi { * @param handler */ public static void getTeamDiaryList(int uid, int teamId, int year, - int week, int pageIndex, AsyncHttpResponseHandler handler) { + int week, int pageIndex, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("uid", uid); params.put("teamid", teamId); @@ -324,19 +306,17 @@ public class OSChinaTeamApi { /*** * 任务、周报、讨论的回复列表 - * - * @author 火蚁 2015-2-2 上午11:39:04 - * - * @return void + * * @param teamId * @param id - * @param type - * 评论列表的类型(周报diary,讨论discuss,任务issue) + * @param type 评论列表的类型(周报diary,讨论discuss,任务issue) * @param pageIndex * @param handler + * @return void + * @author 火蚁 2015-2-2 上午11:39:04 */ public static void getTeamReplyList(int teamId, int id, String type, - int pageIndex, AsyncHttpResponseHandler handler) { + int pageIndex, AsyncHttpResponseHandler handler) { RequestParams params = new RequestParams(); params.put("teamid", teamId); params.put("id", id); @@ -349,20 +329,19 @@ public class OSChinaTeamApi { /*** * 发表一个新的团队动态 - * - * @author 火蚁 2015-3-9 下午2:46:13 - * - * @return void + * * @param teamId * @param content * @param img * @param handler + * @return void + * @author 火蚁 2015-3-9 下午2:46:13 */ public static void pubTeamNewActive(int teamId, String content, File img, - AsyncHttpResponseHandler handler) { + AsyncHttpResponseHandler handler, Context context) { RequestParams params = new RequestParams(); params.put("teamid", teamId); - params.put("uid", AppContext.getInstance().getLoginUid()); + params.put("uid", AccountHelper.getUserId()); params.put("msg", content); params.put("appid", 3); if (img != null) { @@ -378,19 +357,18 @@ public class OSChinaTeamApi { /*** * 更新子任务属性 - * - * @author 火蚁 2015-3-10 下午4:53:49 - * - * @return void + * * @param teamId * @param target * @param childIssue * @param handler + * @return void + * @author 火蚁 2015-3-10 下午4:53:49 */ public static void updateChildIssue(int teamId, String target, - TeamIssue childIssue, AsyncHttpResponseHandler handler) { + TeamIssue childIssue, AsyncHttpResponseHandler handler, Context context) { RequestParams params = new RequestParams(); - params.put("uid", AppContext.getInstance().getLoginUid()); + params.put("uid", AccountHelper.getUserId()); params.put("teamid", teamId); params.put("childissueid", childIssue.getId()); params.put("target", target); @@ -405,19 +383,18 @@ public class OSChinaTeamApi { /*** * 发表任务评论 - * - * @author 火蚁 2015-3-13 下午6:22:41 - * - * @return void + * * @param teamId * @param issueId * @param content * @param handler + * @return void + * @author 火蚁 2015-3-13 下午6:22:41 */ public static void pubTeamIssueReply(int teamId, int issueId, - String content, AsyncHttpResponseHandler handler) { + String content, AsyncHttpResponseHandler handler, Context context) { RequestParams params = new RequestParams(); - params.put("uid", AppContext.getInstance().getLoginUid()); + params.put("uid", AccountHelper.getUserId()); params.put("teamid", teamId); params.put("content", content); params.put("issueid", issueId); diff --git a/app/src/main/java/net/oschina/app/base/BaseActivity.java b/app/src/main/java/net/oschina/app/base/BaseActivity.java index 99c32cd5802a89115de2d82d4d62bc1b035725e5..ab1ef15e73e3282afa98edb14f29ab7d871c46b3 100644 --- a/app/src/main/java/net/oschina/app/base/BaseActivity.java +++ b/app/src/main/java/net/oschina/app/base/BaseActivity.java @@ -3,20 +3,18 @@ package net.oschina.app.base; import android.app.ProgressDialog; import android.os.Bundle; import android.support.v7.app.ActionBar; -import android.support.v7.app.ActionBarActivity; +import android.support.v7.app.AppCompatActivity; import android.view.LayoutInflater; -import android.view.Menu; import android.view.MenuItem; import android.view.View; -import android.widget.TextView; -import net.oschina.app.AppContext; -import net.oschina.app.AppManager; +import com.umeng.analytics.MobclickAgent; + import net.oschina.app.R; +import net.oschina.app.improve.utils.DialogHelper; import net.oschina.app.interf.BaseViewInterface; import net.oschina.app.ui.dialog.CommonToast; import net.oschina.app.ui.dialog.DialogControl; -import net.oschina.app.util.DialogHelp; import net.oschina.app.util.TDevice; import org.kymjs.kjframe.utils.StringUtils; @@ -25,39 +23,27 @@ import butterknife.ButterKnife; /** * baseActionBar Activity - * + * * @author FireAnt(http://my.oschina.net/LittleDY) * @created 2014年9月25日 上午11:30:15 引用自:tonlin */ -public abstract class BaseActivity extends ActionBarActivity implements +public abstract class BaseActivity extends AppCompatActivity implements DialogControl, View.OnClickListener, BaseViewInterface { - public static final String INTENT_ACTION_EXIT_APP = "INTENT_ACTION_EXIT_APP"; - private boolean _isVisible; private ProgressDialog _waitDialog; protected LayoutInflater mInflater; protected ActionBar mActionBar; - private TextView mTvActionTitle; - @Override - protected void onDestroy() { - super.onDestroy(); - TDevice.hideSoftKeyboard(getCurrentFocus()); - ButterKnife.reset(this); - } + private final String packageName4Umeng = this.getClass().getName(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - if (AppContext.getNightModeSwitch()) { - setTheme(R.style.AppBaseTheme_Night); + if (false) { + setTheme(R.style.App_Theme_Night); } else { - setTheme(R.style.AppBaseTheme_Light); - } - AppManager.getAppManager().addActivity(this); - if (!hasActionBar()) { - // supportRequestWindowFeature(Window.FEATURE_NO_TITLE); + setTheme(R.style.App_Theme_Light); } onBeforeSetContentLayout(); if (getLayoutId() != 0) { @@ -70,18 +56,42 @@ public abstract class BaseActivity extends ActionBarActivity implements } // 通过注解绑定控件 - ButterKnife.inject(this); + ButterKnife.bind(this); init(savedInstanceState); initView(); initData(); _isVisible = true; + + //umeng analytics + MobclickAgent.setDebugMode(false); + MobclickAgent.openActivityDurationTrack(false); + MobclickAgent.setScenarioType(this, MobclickAgent.EScenarioType.E_UM_NORMAL); + } + + @Override + protected void onPause() { + super.onPause(); + MobclickAgent.onPageEnd(this.packageName4Umeng); + MobclickAgent.onResume(this); + + if (this.isFinishing()) { + TDevice.hideSoftKeyboard(getCurrentFocus()); + } } - protected void onBeforeSetContentLayout() {} + @Override + protected void onResume() { + super.onResume(); + MobclickAgent.onPageStart(this.packageName4Umeng); + MobclickAgent.onResume(this); + } + + protected void onBeforeSetContentLayout() { + } protected boolean hasActionBar() { - return true; + return getSupportActionBar() != null; } protected int getLayoutId() { @@ -100,7 +110,8 @@ public abstract class BaseActivity extends ActionBarActivity implements return false; } - protected void init(Bundle savedInstanceState) {} + protected void init(Bundle savedInstanceState) { + } protected void initActionBar(ActionBar actionBar) { if (actionBar == null) @@ -129,9 +140,6 @@ public abstract class BaseActivity extends ActionBarActivity implements title = getString(R.string.app_name); } if (hasActionBar() && mActionBar != null) { - if (mTvActionTitle != null) { - mTvActionTitle.setText(title); - } mActionBar.setTitle(title); } } @@ -139,26 +147,16 @@ public abstract class BaseActivity extends ActionBarActivity implements @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case android.R.id.home: - onBackPressed(); - break; + case android.R.id.home: + onBackPressed(); + break; - default: - break; + default: + break; } return super.onOptionsItemSelected(item); } - @Override - protected void onPause() { - super.onPause(); - } - - @Override - protected void onResume() { - super.onResume(); - } - public void showToast(int msgResid, int icon, int gravity) { showToast(getString(msgResid), icon, gravity); } @@ -185,7 +183,7 @@ public abstract class BaseActivity extends ActionBarActivity implements public ProgressDialog showWaitDialog(String message) { if (_isVisible) { if (_waitDialog == null) { - _waitDialog = DialogHelp.getWaitDialog(this, message); + _waitDialog = DialogHelper.getProgressDialog(this, message); } if (_waitDialog != null) { _waitDialog.setMessage(message); @@ -207,11 +205,4 @@ public abstract class BaseActivity extends ActionBarActivity implements } } } - - @Override - public boolean onMenuOpened(int featureId, Menu menu) { - - // setOverflowIconVisible(featureId, menu); - return super.onMenuOpened(featureId, menu); - } } diff --git a/app/src/main/java/net/oschina/app/base/BaseApplication.java b/app/src/main/java/net/oschina/app/base/BaseApplication.java index 975c33f795db1ec96c248a3af38455603d3059ef..7c171e5ab97437c8757fae5794e49fb6f90ab8e9 100644 --- a/app/src/main/java/net/oschina/app/base/BaseApplication.java +++ b/app/src/main/java/net/oschina/app/base/BaseApplication.java @@ -1,135 +1,49 @@ package net.oschina.app.base; import android.annotation.SuppressLint; -import android.annotation.TargetApi; -import android.app.Activity; import android.app.Application; import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; -import android.content.res.Resources; -import android.os.Build; -import android.util.DisplayMetrics; +import android.support.v4.content.SharedPreferencesCompat; import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.ImageView; -import android.widget.TextView; import android.widget.Toast; -import net.oschina.app.R; -import net.oschina.app.util.StringUtils; +import net.oschina.app.improve.widget.SimplexToast; @SuppressLint("InflateParams") public class BaseApplication extends Application { - private static String PREF_NAME = "creativelocker.pref"; - private static String LAST_REFRESH_TIME = "last_refresh_time.pref"; + private static final String PREF_NAME = "creativelocker.pref"; static Context _context; - static Resources _resource; - private static String lastToast = ""; - private static long lastToastTime; - - private static boolean sIsAtLeastGB; - - static { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { - sIsAtLeastGB = true; - } - } @Override public void onCreate() { super.onCreate(); _context = getApplicationContext(); - _resource = _context.getResources(); + //LeakCanary.install(this); } public static synchronized BaseApplication context() { return (BaseApplication) _context; } - public static Resources resources() { - return _resource; - } - - /** - * 放入已读文章列表中 - * - */ - public static void putReadedPostList(String prefFileName, String key, - String value) { - SharedPreferences preferences = getPreferences(prefFileName); - int size = preferences.getAll().size(); - Editor editor = preferences.edit(); - if (size >= 100) { - editor.clear(); - } - editor.putString(key, value); - apply(editor); - } - - /** - * 读取是否是已读的文章列表 - * - * @return - */ - public static boolean isOnReadedPostList(String prefFileName, String key) { - return getPreferences(prefFileName).contains(key); - } - - /** - * 记录列表上次刷新时间 - * - * @param key - * @param value - * @return void - * @author 火蚁 - * 2015-2-9 下午2:21:37 - */ - public static void putToLastRefreshTime(String key, String value) { - SharedPreferences preferences = getPreferences(LAST_REFRESH_TIME); - Editor editor = preferences.edit(); - editor.putString(key, value); - apply(editor); - } - - /** - * 获取列表的上次刷新时间 - * - * @param key - * @return - * @author 火蚁 - * 2015-2-9 下午2:22:04 - */ - public static String getLastRefreshTime(String key) { - return getPreferences(LAST_REFRESH_TIME).getString(key, StringUtils.getCurTimeStr()); - } - - @TargetApi(Build.VERSION_CODES.GINGERBREAD) - public static void apply(SharedPreferences.Editor editor) { - if (sIsAtLeastGB) { - editor.apply(); - } else { - editor.commit(); - } - } public static void set(String key, int value) { Editor editor = getPreferences().edit(); editor.putInt(key, value); - apply(editor); + SharedPreferencesCompat.EditorCompat.getInstance().apply(editor); } public static void set(String key, boolean value) { Editor editor = getPreferences().edit(); editor.putBoolean(key, value); - apply(editor); + SharedPreferencesCompat.EditorCompat.getInstance().apply(editor); } public static void set(String key, String value) { Editor editor = getPreferences().edit(); editor.putString(key, value); - apply(editor); + SharedPreferencesCompat.EditorCompat.getInstance().apply(editor); } public static boolean get(String key, boolean defValue) { @@ -152,41 +66,8 @@ public class BaseApplication extends Application { return getPreferences().getFloat(key, defValue); } - @TargetApi(Build.VERSION_CODES.HONEYCOMB) public static SharedPreferences getPreferences() { - SharedPreferences pre = context().getSharedPreferences(PREF_NAME, - Context.MODE_MULTI_PROCESS); - return pre; - } - - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - public static SharedPreferences getPreferences(String prefName) { - return context().getSharedPreferences(prefName, - Context.MODE_MULTI_PROCESS); - } - - public static int[] getDisplaySize() { - return new int[]{getPreferences().getInt("screen_width", 480), - getPreferences().getInt("screen_height", 854)}; - } - - public static void saveDisplaySize(Activity activity) { - DisplayMetrics displaymetrics = new DisplayMetrics(); - activity.getWindowManager().getDefaultDisplay() - .getMetrics(displaymetrics); - SharedPreferences.Editor editor = getPreferences().edit(); - editor.putInt("screen_width", displaymetrics.widthPixels); - editor.putInt("screen_height", displaymetrics.heightPixels); - editor.putFloat("density", displaymetrics.density); - editor.commit(); - } - - public static String string(int id) { - return _resource.getString(id); - } - - public static String string(int id, Object... args) { - return _resource.getString(id, args); + return context().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); } public static void showToast(int message) { @@ -231,34 +112,7 @@ public class BaseApplication extends Application { showToast(context().getString(message, args), duration, icon, gravity); } - public static void showToast(String message, int duration, int icon, - int gravity) { - if (message != null && !message.equalsIgnoreCase("")) { - long time = System.currentTimeMillis(); - if (!message.equalsIgnoreCase(lastToast) - || Math.abs(time - lastToastTime) > 2000) { - View view = LayoutInflater.from(context()).inflate( - R.layout.view_toast, null); - ((TextView) view.findViewById(R.id.title_tv)).setText(message); - if (icon != 0) { - ((ImageView) view.findViewById(R.id.icon_iv)) - .setImageResource(icon); - ((ImageView) view.findViewById(R.id.icon_iv)) - .setVisibility(View.VISIBLE); - } - Toast toast = new Toast(context()); - toast.setView(view); - if (gravity == Gravity.CENTER) { - toast.setGravity(gravity, 0, 0); - } else { - toast.setGravity(gravity, 0, 35); - } - - toast.setDuration(duration); - toast.show(); - lastToast = message; - lastToastTime = System.currentTimeMillis(); - } - } + public static void showToast(String message, int duration, int icon, int gravity) { + SimplexToast.show(_context, message, gravity, duration); } } diff --git a/app/src/main/java/net/oschina/app/base/BaseFragment.java b/app/src/main/java/net/oschina/app/base/BaseFragment.java index 73caa6d8bc12ea6d157c2dbc21a146586b9b77b2..52a46b1d2f58c685365fb021ebb39f3cc8c9d0f1 100644 --- a/app/src/main/java/net/oschina/app/base/BaseFragment.java +++ b/app/src/main/java/net/oschina/app/base/BaseFragment.java @@ -15,10 +15,10 @@ import net.oschina.app.ui.dialog.DialogControl; /** * 碎片基类 - * + * * @author FireAnt(http://my.oschina.net/LittleDY) * @created 2014年9月25日 上午11:18:46 - * + * */ public class BaseFragment extends Fragment implements android.view.View.OnClickListener, BaseFragmentInterface { diff --git a/app/src/main/java/net/oschina/app/base/BaseListFragment.java b/app/src/main/java/net/oschina/app/base/BaseListFragment.java index f7790bbee384f7942e6babe27628bf2a68d2fee2..492276cc4beeda256a74f1fa830b94822f8fd7f1 100644 --- a/app/src/main/java/net/oschina/app/base/BaseListFragment.java +++ b/app/src/main/java/net/oschina/app/base/BaseListFragment.java @@ -30,7 +30,6 @@ import net.oschina.app.util.TDevice; import net.oschina.app.util.ThemeSwitchUtils; import net.oschina.app.util.XmlUtils; -import cz.msebera.android.httpclient.Header; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.Serializable; @@ -38,25 +37,25 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; +import butterknife.Bind; import butterknife.ButterKnife; -import butterknife.InjectView; +import cz.msebera.android.httpclient.Header; @SuppressLint("NewApi") public abstract class BaseListFragment extends BaseFragment - implements SwipeRefreshLayout.OnRefreshListener, OnItemClickListener, - OnScrollListener { + implements SwipeRefreshLayout.OnRefreshListener, OnItemClickListener, OnScrollListener { public static final String BUNDLE_KEY_CATALOG = "BUNDLE_KEY_CATALOG"; - @InjectView(R.id.swiperefreshlayout) + @Bind(R.id.swiperefreshlayout) protected SwipeRefreshLayout mSwipeRefreshLayout; - @InjectView(R.id.listview) + @Bind(R.id.listview) protected ListView mListView; protected ListBaseAdapter mAdapter; - @InjectView(R.id.error_layout) + @Bind(R.id.error_layout) protected EmptyLayout mErrorLayout; protected int mStoreEmptyState = -1; @@ -69,6 +68,36 @@ public abstract class BaseListFragment extends BaseFragment private AsyncTask> mCacheTask; private ParserTask mParserTask; + protected AsyncHttpResponseHandler mHandler = new AsyncHttpResponseHandler() { + + @Override + public void onSuccess(int statusCode, Header[] headers, + byte[] responseBytes) { + if (mCurrentPage == 0 && needAutoRefresh()) { + //AppContext.putToLastRefreshTime(getCacheKey(), + // StringUtils.getCurrentTimeStr()); + } + if (isAdded()) { + if (mState == STATE_REFRESH) { + onRefreshNetworkSuccess(); + } + executeParserTask(responseBytes); + } else { + executeOnLoadFinish(); + } + } + + @Override + public void onFailure(int arg0, Header[] arg1, byte[] arg2, + Throwable arg3) { + if (isAdded()) { + readCacheData(getCacheKey()); + } else { + executeOnLoadFinish(); + } + } + + }; @Override protected int getLayoutId() { @@ -77,7 +106,8 @@ public abstract class BaseListFragment extends BaseFragment @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { + Bundle savedInstanceState) { + mInflater = inflater; View view = inflater.inflate(getLayoutId(), container, false); return view; } @@ -85,7 +115,7 @@ public abstract class BaseListFragment extends BaseFragment @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - ButterKnife.inject(this, view); + ButterKnife.bind(this, view); initView(view); } @@ -187,11 +217,11 @@ public abstract class BaseListFragment extends BaseFragment @Override public void onItemClick(AdapterView parent, View view, int position, - long id) {} + long id) { + } private String getCacheKey() { - return new StringBuilder(getCacheKeyPrefix()).append("_") - .append(mCurrentPage).toString(); + return getCacheKeyPrefix() + "_" + mCurrentPage; } // 是否需要自动刷新 @@ -202,11 +232,9 @@ public abstract class BaseListFragment extends BaseFragment /*** * 获取列表数据 * - * - * @author 火蚁 2015-2-9 下午3:16:12 - * - * @return void * @param refresh + * @return void + * @author 火蚁 2015-2-9 下午3:16:12 */ protected void requestData(boolean refresh) { String key = getCacheKey(); @@ -221,11 +249,9 @@ public abstract class BaseListFragment extends BaseFragment /*** * 判断是否需要读取缓存的数据 * - * @author 火蚁 2015-2-10 下午2:41:02 - * - * @return boolean * @param refresh * @return + * @author 火蚁 2015-2-10 下午2:41:02 */ protected boolean isReadCacheData(boolean refresh) { String key = getCacheKey(); @@ -249,21 +275,19 @@ public abstract class BaseListFragment extends BaseFragment // 是否到时间去刷新数据了 private boolean onTimeRefresh() { - String lastRefreshTime = AppContext.getLastRefreshTime(getCacheKey()); - String currTime = StringUtils.getCurTimeStr(); + String lastRefreshTime = "0";//AppContext.getLastRefreshTime(getCacheKey()); + String currTime = StringUtils.getCurrentTimeStr(); long diff = StringUtils.calDateDifferent(lastRefreshTime, currTime); return needAutoRefresh() && diff > getAutoRefreshTime(); } /*** * 自动刷新的时间 - * + *

* 默认:自动刷新的时间为半天时间 * - * @author 火蚁 2015-2-9 下午5:55:11 - * - * @return long * @return + * @author 火蚁 2015-2-9 下午5:55:11 */ protected long getAutoRefreshTime() { return 12 * 60 * 60; @@ -277,7 +301,8 @@ public abstract class BaseListFragment extends BaseFragment } } - protected void sendRequestData() {} + protected void sendRequestData() { + } private void readCacheData(String cacheKey) { cancelReadCacheTask(); @@ -291,80 +316,6 @@ public abstract class BaseListFragment extends BaseFragment } } - private class CacheTask extends AsyncTask> { - private final WeakReference mContext; - - private CacheTask(Context context) { - mContext = new WeakReference(context); - } - - @Override - protected ListEntity doInBackground(String... params) { - Serializable seri = CacheManager.readObject(mContext.get(), - params[0]); - if (seri == null) { - return null; - } else { - return readList(seri); - } - } - - @Override - protected void onPostExecute(ListEntity list) { - super.onPostExecute(list); - if (list != null) { - executeOnLoadDataSuccess(list.getList()); - } else { - executeOnLoadDataError(null); - } - executeOnLoadFinish(); - } - } - - private class SaveCacheTask extends AsyncTask { - private final WeakReference mContext; - private final Serializable seri; - private final String key; - - private SaveCacheTask(Context context, Serializable seri, String key) { - mContext = new WeakReference(context); - this.seri = seri; - this.key = key; - } - - @Override - protected Void doInBackground(Void... params) { - CacheManager.saveObject(mContext.get(), seri, key); - return null; - } - } - - protected AsyncHttpResponseHandler mHandler = new AsyncHttpResponseHandler() { - - @Override - public void onSuccess(int statusCode, Header[] headers, - byte[] responseBytes) { - if (mCurrentPage == 0 && needAutoRefresh()) { - AppContext.putToLastRefreshTime(getCacheKey(), - StringUtils.getCurTimeStr()); - } - if (isAdded()) { - if (mState == STATE_REFRESH) { - onRefreshNetworkSuccess(); - } - executeParserTask(responseBytes); - } - } - - @Override - public void onFailure(int arg0, Header[] arg1, byte[] arg2, - Throwable arg3) { - if (isAdded()) { - readCacheData(getCacheKey()); - } - } - }; - protected void executeOnLoadDataSuccess(List data) { if (data == null) { data = new ArrayList(); @@ -373,7 +324,7 @@ public abstract class BaseListFragment extends BaseFragment if (mResult != null && !mResult.OK()) { AppContext.showToast(mResult.getErrorMessage()); // 注销登陆,密码已经修改,cookie,失效了 - AppContext.getInstance().Logout(); + //AppContext.getInstance().Logout(); } mErrorLayout.setErrorType(EmptyLayout.HIDE_LAYOUT); @@ -415,7 +366,6 @@ public abstract class BaseListFragment extends BaseFragment * 是否需要隐藏listview,显示无数据状态 * * @author 火蚁 2015-1-27 下午6:18:59 - * */ protected boolean needShowEmptyNoData() { return true; @@ -437,7 +387,8 @@ public abstract class BaseListFragment extends BaseFragment return AppContext.PAGE_SIZE; } - protected void onRefreshNetworkSuccess() {} + protected void onRefreshNetworkSuccess() { + } protected void executeOnLoadDataError(String error) { if (mCurrentPage == 0 @@ -445,9 +396,9 @@ public abstract class BaseListFragment extends BaseFragment mErrorLayout.setErrorType(EmptyLayout.NETWORK_ERROR); } else { - //在无网络时,滚动到底部时,mCurrentPage先自加了,然而在失败时却 - //没有减回来,如果刻意在无网络的情况下上拉,可以出现漏页问题 - //find by TopJohn + //在无网络时,滚动到底部时,mCurrentPage先自加了,然而在失败时却 + //没有减回来,如果刻意在无网络的情况下上拉,可以出现漏页问题 + //find by TopJohn mCurrentPage--; mErrorLayout.setErrorType(EmptyLayout.HIDE_LAYOUT); @@ -462,7 +413,9 @@ public abstract class BaseListFragment extends BaseFragment mState = STATE_NONE; } - /** 设置顶部正在加载的状态 */ + /** + * 设置顶部正在加载的状态 + */ protected void setSwipeRefreshLoadingState() { if (mSwipeRefreshLayout != null) { mSwipeRefreshLayout.setRefreshing(true); @@ -471,7 +424,9 @@ public abstract class BaseListFragment extends BaseFragment } } - /** 设置顶部加载完毕的状态 */ + /** + * 设置顶部加载完毕的状态 + */ protected void setSwipeRefreshLoadedState() { if (mSwipeRefreshLayout != null) { mSwipeRefreshLayout.setRefreshing(false); @@ -492,50 +447,6 @@ public abstract class BaseListFragment extends BaseFragment } } - class ParserTask extends AsyncTask { - - private final byte[] reponseData; - private boolean parserError; - private List list; - - public ParserTask(byte[] data) { - this.reponseData = data; - } - - @Override - protected String doInBackground(Void... params) { - try { - ListEntity data = parseList(new ByteArrayInputStream( - reponseData)); - new SaveCacheTask(getActivity(), data, getCacheKey()).execute(); - list = data.getList(); - if (list == null) { - ResultBean resultBean = XmlUtils.toBean(ResultBean.class, - reponseData); - if (resultBean != null) { - mResult = resultBean.getResult(); - } - } - } catch (Exception e) { - e.printStackTrace(); - - parserError = true; - } - return null; - } - - @Override - protected void onPostExecute(String result) { - super.onPostExecute(result); - if (parserError) { - readCacheData(getCacheKey()); - } else { - executeOnLoadDataSuccess(list); - executeOnLoadFinish(); - } - } - } - @Override public void onScrollStateChanged(AbsListView view, int scrollState) { if (mAdapter == null || mAdapter.getCount() == 0) { @@ -568,7 +479,7 @@ public abstract class BaseListFragment extends BaseFragment @Override public void onScroll(AbsListView view, int firstVisibleItem, - int visibleItemCount, int totalItemCount) { + int visibleItemCount, int totalItemCount) { // 数据已经全部加载,或数据为空时,或正在加载,不处理滚动事件 // if (mState == STATE_NOMORE || mState == STATE_LOADMORE // || mState == STATE_REFRESH) { @@ -589,18 +500,85 @@ public abstract class BaseListFragment extends BaseFragment /** * 保存已读的文章列表 - * - * @param view - * @param prefFileName - * @param key */ protected void saveToReadedList(final View view, final String prefFileName, - final String key) { - // 放入已读列表 - AppContext.putReadedPostList(prefFileName, key, "true"); + final String key) { TextView tvTitle = (TextView) view.findViewById(R.id.tv_title); if (tvTitle != null) { tvTitle.setTextColor(AppContext.getInstance().getResources().getColor(ThemeSwitchUtils.getTitleReadedColor())); } } + + private class CacheTask extends AsyncTask> { + private final WeakReference mContext; + + private CacheTask(Context context) { + mContext = new WeakReference(context); + } + + @Override + protected ListEntity doInBackground(String... params) { + Serializable seri = CacheManager.readObject(mContext.get(), + params[0]); + if (seri == null) { + return null; + } else { + return readList(seri); + } + } + + @Override + protected void onPostExecute(ListEntity list) { + super.onPostExecute(list); + if (list != null) { + executeOnLoadDataSuccess(list.getList()); + } else { + executeOnLoadDataError(null); + } + executeOnLoadFinish(); + } + } + + class ParserTask extends AsyncTask { + + private final byte[] reponseData; + private boolean parserError; + private List list; + + public ParserTask(byte[] data) { + this.reponseData = data; + } + + @Override + protected String doInBackground(Void... params) { + try { + final ListEntity data = parseList(new ByteArrayInputStream( + reponseData)); + CacheManager.saveObject(getActivity(), data, getCacheKey()); + list = data.getList(); + if (list == null) { + ResultBean resultBean = XmlUtils.toBean(ResultBean.class, + reponseData); + if (resultBean != null) { + mResult = resultBean.getResult(); + } + } + } catch (Exception e) { + e.printStackTrace(); + parserError = true; + } + return null; + } + + @Override + protected void onPostExecute(String result) { + super.onPostExecute(result); + if (parserError) { + readCacheData(getCacheKey()); + } else { + executeOnLoadDataSuccess(list); + executeOnLoadFinish(); + } + } + } } diff --git a/app/src/main/java/net/oschina/app/base/BaseNewActivity.java b/app/src/main/java/net/oschina/app/base/BaseNewActivity.java deleted file mode 100644 index 77a7283aebf500fd0e0cf35dcef8f5fd92bb2f44..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/base/BaseNewActivity.java +++ /dev/null @@ -1,11 +0,0 @@ -package net.oschina.app.base; - -import android.support.v7.app.AppCompatActivity; - -/** - * Created by 火蚁 on 15/5/18. - */ -public class BaseNewActivity extends AppCompatActivity { - - -} diff --git a/app/src/main/java/net/oschina/app/base/BaseViewPagerFragment.java b/app/src/main/java/net/oschina/app/base/BaseViewPagerFragment.java index f7b55f2c5c6ebc0866603f38d7c3c5a3a6b0cd52..8b9af1180503538381c53dc90d3e7b818d7c975d 100644 --- a/app/src/main/java/net/oschina/app/base/BaseViewPagerFragment.java +++ b/app/src/main/java/net/oschina/app/base/BaseViewPagerFragment.java @@ -1,37 +1,61 @@ package net.oschina.app.base; -import net.oschina.app.R; -import net.oschina.app.adapter.ViewPageFragmentAdapter; -import net.oschina.app.ui.empty.EmptyLayout; -import net.oschina.app.widget.PagerSlidingTabStrip; import android.os.Bundle; import android.support.v4.view.ViewPager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import net.oschina.app.R; +import net.oschina.app.adapter.ViewPageFragmentAdapter; +import net.oschina.app.ui.empty.EmptyLayout; +import net.oschina.app.widget.PagerSlidingTabStrip; + /** * 带有导航条的基类 - * + * * @author FireAnt(http://my.oschina.net/LittleDY) * @created 2014年11月6日 下午4:59:50 - * */ public abstract class BaseViewPagerFragment extends BaseFragment { + private static final String TAG = "BaseViewPagerFragment"; protected PagerSlidingTabStrip mTabStrip; protected ViewPager mViewPager; protected ViewPageFragmentAdapter mTabsAdapter; protected EmptyLayout mErrorLayout; + protected View mRoot; + + @Override + public void onDestroyView() { + super.onDestroyView(); + } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - return inflater.inflate(R.layout.base_viewpage_fragment, null); + Bundle savedInstanceState) { + if (mRoot == null) { + View root = inflater.inflate(R.layout.base_viewpage_fragment, null); + + mTabStrip = (PagerSlidingTabStrip) root + .findViewById(R.id.pager_tabstrip); + + mViewPager = (ViewPager) root.findViewById(R.id.pager); + + mErrorLayout = (EmptyLayout) root.findViewById(R.id.error_layout); + + mTabsAdapter = new ViewPageFragmentAdapter(getChildFragmentManager(), + mTabStrip, mViewPager); + setScreenPageLimit(); + mRoot = root; + onSetupTabAdapter(mTabsAdapter); + } + return mRoot; } @Override public void onViewCreated(View view, Bundle savedInstanceState) { + /* mTabStrip = (PagerSlidingTabStrip) view .findViewById(R.id.pager_tabstrip); @@ -43,12 +67,13 @@ public abstract class BaseViewPagerFragment extends BaseFragment { mTabStrip, mViewPager); setScreenPageLimit(); onSetupTabAdapter(mTabsAdapter); - // if (savedInstanceState != null) { - // int pos = savedInstanceState.getInt("position"); - // mViewPager.setCurrentItem(pos, true); - // } + */ + if (savedInstanceState != null) { + int pos = savedInstanceState.getInt("position"); + mViewPager.setCurrentItem(pos, true); + } } - + protected void setScreenPageLimit() { } diff --git a/app/src/main/java/net/oschina/app/base/BeseHaveHeaderListFragment.java b/app/src/main/java/net/oschina/app/base/BeseHaveHeaderListFragment.java index b4a85e125d2e7fed6b9705708daffbd07338cf25..279c89ddc09013efe859f36799aabbb86fe363ed 100644 --- a/app/src/main/java/net/oschina/app/base/BeseHaveHeaderListFragment.java +++ b/app/src/main/java/net/oschina/app/base/BeseHaveHeaderListFragment.java @@ -1,24 +1,24 @@ package net.oschina.app.base; -import java.io.ByteArrayInputStream; -import java.io.Serializable; -import java.lang.ref.WeakReference; - -import net.oschina.app.bean.Entity; -import net.oschina.app.cache.CacheManager; -import net.oschina.app.ui.empty.EmptyLayout; - -import cz.msebera.android.httpclient.Header; - import android.app.Activity; import android.content.Context; import android.os.AsyncTask; import android.os.Bundle; import android.view.View; -import butterknife.ButterKnife; import com.loopj.android.http.AsyncHttpResponseHandler; +import net.oschina.app.bean.Entity; +import net.oschina.app.cache.CacheManager; +import net.oschina.app.ui.empty.EmptyLayout; + +import java.io.ByteArrayInputStream; +import java.io.Serializable; +import java.lang.ref.WeakReference; + +import butterknife.ButterKnife; +import cz.msebera.android.httpclient.Header; + /** * 需要加入header的BaseListFragment * @@ -71,7 +71,7 @@ public abstract class BeseHaveHeaderListFragment extends BaseF private AsyncTask mCacheTask; + private ShareDialog mDialog; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -84,7 +86,7 @@ public abstract class CommonDetailFragment extends BaseF mCommentCount = getActivity().getIntent().getIntExtra("comment_count", 0); mId = getActivity().getIntent().getIntExtra("id", 0); - ButterKnife.inject(this, view); + ButterKnife.bind(this, view); initView(view); initData(); requestData(false); @@ -117,6 +119,7 @@ public abstract class CommonDetailFragment extends BaseF @Override public void onDestroyView() { recycleWebView(); + mDialog = null; super.onDestroyView(); } @@ -187,7 +190,7 @@ public abstract class CommonDetailFragment extends BaseF if (seri == null) { return null; } else { - return (T)seri; + return (T) seri; } } return null; @@ -218,17 +221,19 @@ public abstract class CommonDetailFragment extends BaseF return; } - mWebView.loadDataWithBaseURL("", this.getWebViewBody(detail), "text/html", "UTF-8", ""); - // 显示存储的字体大小 - mWebView.loadUrl(FontSizeUtils.getSaveFontSize()); - boolean favoriteState = getFavoriteState() == 1; - setFavoriteState(favoriteState); - - // 判断最新的评论数是否大于 - if (getCommentCount() > mCommentCount) { - mCommentCount = getCommentCount(); + if (mWebView != null) { + mWebView.loadDataWithBaseURL("", this.getWebViewBody(detail), "text/html", "UTF-8", ""); + // 显示存储的字体大小 + mWebView.loadUrl(FontSizeUtils.getSaveFontSize()); + boolean favoriteState = getFavoriteState() == 1; + setFavoriteState(favoriteState); + + // 判断最新的评论数是否大于 + if (getCommentCount() > mCommentCount) { + mCommentCount = getCommentCount(); + } + setCommentCount(mCommentCount); } - setCommentCount(mCommentCount); } protected void executeOnLoadDataError() { @@ -295,7 +300,7 @@ public abstract class CommonDetailFragment extends BaseF final String[] items = getResources().getStringArray( R.array.font_size); - fontSizeChange = DialogHelp.getSingleChoiceDialog(getActivity(), items, FontSizeUtils.getSaveFontSizeIndex(), new DialogInterface.OnClickListener() { + fontSizeChange = DialogHelper.getSingleChoiceDialog(getActivity(), "", items, FontSizeUtils.getSaveFontSizeIndex(), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { // 更改字体大小 @@ -315,11 +320,11 @@ public abstract class CommonDetailFragment extends BaseF AppContext.showToastShort(R.string.tip_no_internet); return; } - if (!AppContext.getInstance().isLogin()) { + if (!AccountHelper.isLogin()) { UIHelper.showLoginActivity(getActivity()); return; } - int uid = AppContext.getInstance().getLoginUid(); + int uid = (int) AccountHelper.getUserId(); final boolean isFavorited = getFavoriteState() == 1 ? true : false; AsyncHttpResponseHandler mFavoriteHandler = new AsyncHttpResponseHandler() { @@ -381,7 +386,7 @@ public abstract class CommonDetailFragment extends BaseF if (mId == 0 || mDetail == null) { AppContext.showToast("正在加载,请稍等..."); } - if (!AppContext.getInstance().isLogin()) { + if (!AccountHelper.isLogin()) { UIHelper.showLoginActivity(getActivity()); return; } @@ -430,6 +435,7 @@ public abstract class CommonDetailFragment extends BaseF }); dialog.show(); } + // 分享 public void handleShare() { if (mDetail == null || TextUtils.isEmpty(getShareContent()) @@ -437,13 +443,15 @@ public abstract class CommonDetailFragment extends BaseF AppContext.showToast("内容加载失败..."); return; } - final ShareDialog dialog = new ShareDialog(getActivity()); - dialog.setCancelable(true); - dialog.setCanceledOnTouchOutside(true); - dialog.setTitle(R.string.share_to); - dialog.setShareInfo(getShareTitle(), getShareContent(), getShareUrl()); - dialog.show(); + if (mDialog == null) + mDialog = new ShareDialog(getActivity()); + mDialog.setCancelable(true); + mDialog.setCanceledOnTouchOutside(true); + mDialog.setTitle(R.string.share_to); + mDialog.setShareInfo(getShareTitle(), getShareContent(), getShareUrl()); + mDialog.show(); } + // 显示评论列表 public void onCilckShowComment() { showCommentView(); @@ -488,7 +496,9 @@ public abstract class CommonDetailFragment extends BaseF @Override public void onFinish() { ((DetailActivity) getActivity()).emojiFragment.hideAllKeyBoard(); - }; + } + + ; }; // 发表评论 @@ -498,7 +508,7 @@ public abstract class CommonDetailFragment extends BaseF AppContext.showToastShort(R.string.tip_network_error); return; } - if (!AppContext.getInstance().isLogin()) { + if (!AccountHelper.isLogin()) { UIHelper.showLoginActivity(getActivity()); return; } @@ -508,8 +518,7 @@ public abstract class CommonDetailFragment extends BaseF } showWaitDialog(R.string.progress_submit); - OSChinaApi.publicComment(getCommentType(), mId, AppContext - .getInstance().getLoginUid(), str.toString(), 0, + OSChinaApi.publicComment(getCommentType(), mId, (int) AccountHelper.getUserId(), str.toString(), 0, mCommentHandler); } @@ -532,27 +541,48 @@ public abstract class CommonDetailFragment extends BaseF // 获取缓存的key protected abstract String getCacheKey(); + // 从网络中读取数据 protected abstract void sendRequestDataForNet(); + // 解析数据 protected abstract T parseData(InputStream is); + // 返回填充到webview中的内容 protected abstract String getWebViewBody(T detail); + // 显示评论列表 protected abstract void showCommentView(); + // 获取评论的类型 protected abstract int getCommentType(); + protected abstract String getShareTitle(); + protected abstract String getShareContent(); + protected abstract String getShareUrl(); + // 返回举报的url - protected String getRepotrUrl() {return "";} + protected String getRepotrUrl() { + return ""; + } + // 返回举报的类型 - protected byte getReportType() {return Report.TYPE_QUESTION;} + protected byte getReportType() { + return Report.TYPE_QUESTION; + } // 获取收藏类型(如新闻、博客、帖子) protected abstract int getFavoriteTargetType(); + protected abstract int getFavoriteState(); + protected abstract void updateFavoriteChanged(int newFavoritedState); + protected abstract int getCommentCount(); + + public ShareDialog getDialog() { + return mDialog; + } } diff --git a/app/src/main/java/net/oschina/app/base/ListBaseAdapter.java b/app/src/main/java/net/oschina/app/base/ListBaseAdapter.java index 4468bc4c74de089e8a029212fd3d4bf2f6f67e54..ff37c728bf2476becf41aba84832b683fdc0ea70 100644 --- a/app/src/main/java/net/oschina/app/base/ListBaseAdapter.java +++ b/app/src/main/java/net/oschina/app/base/ListBaseAdapter.java @@ -1,7 +1,9 @@ package net.oschina.app.base; + import android.annotation.SuppressLint; import android.content.Context; +import android.support.annotation.DrawableRes; import android.text.Html; import android.text.Spanned; import android.text.TextUtils; @@ -9,6 +11,7 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; +import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; @@ -43,6 +46,12 @@ public class ListBaseAdapter extends BaseAdapter { private LayoutInflater mInflater; + protected Context mContext; + + public ListBaseAdapter(Context context) { + mContext = context; + } + protected LayoutInflater getLayoutInflater(Context context) { if (mInflater == null) { mInflater = (LayoutInflater) context @@ -91,8 +100,8 @@ public class ListBaseAdapter extends BaseAdapter { return getDataSize(); } - public int getDataSizePlus1(){ - if(hasFooterView()){ + public int getDataSizePlus1() { + if (hasFooterView()) { return getDataSize() + 1; } return getDataSize(); @@ -175,7 +184,7 @@ public class ListBaseAdapter extends BaseAdapter { @SuppressLint("InflateParams") @Override public View getView(int position, View convertView, ViewGroup parent) { - if (position == getCount() - 1&&hasFooterView()) {// 最后一条 + if (position == getCount() - 1 && hasFooterView()) {// 最后一条 // if (position < _data.size()) { // position = getCount() - 2; // footview // } @@ -192,35 +201,35 @@ public class ListBaseAdapter extends BaseAdapter { .findViewById(R.id.progressbar); TextView text = (TextView) mFooterView.findViewById(R.id.text); switch (getState()) { - case STATE_LOAD_MORE: - setFooterViewLoading(); - break; - case STATE_NO_MORE: - mFooterView.setVisibility(View.VISIBLE); - progress.setVisibility(View.GONE); - text.setVisibility(View.VISIBLE); - text.setText(_loadFinishText); - break; - case STATE_EMPTY_ITEM: - progress.setVisibility(View.GONE); - mFooterView.setVisibility(View.VISIBLE); - text.setText(_noDateText); - break; - case STATE_NETWORK_ERROR: - mFooterView.setVisibility(View.VISIBLE); - progress.setVisibility(View.GONE); - text.setVisibility(View.VISIBLE); - if (TDevice.hasInternet()) { - text.setText("加载出错了"); - } else { - text.setText("没有可用的网络"); - } - break; - default: - progress.setVisibility(View.GONE); - mFooterView.setVisibility(View.GONE); - text.setVisibility(View.GONE); - break; + case STATE_LOAD_MORE: + setFooterViewLoading(); + break; + case STATE_NO_MORE: + mFooterView.setVisibility(View.VISIBLE); + progress.setVisibility(View.GONE); + text.setVisibility(View.VISIBLE); + text.setText(_loadFinishText); + break; + case STATE_EMPTY_ITEM: + progress.setVisibility(View.GONE); + mFooterView.setVisibility(View.VISIBLE); + text.setText(_noDateText); + break; + case STATE_NETWORK_ERROR: + mFooterView.setVisibility(View.VISIBLE); + progress.setVisibility(View.GONE); + text.setVisibility(View.VISIBLE); + if (TDevice.hasInternet()) { + text.setText("加载出错了"); + } else { + text.setText("没有可用的网络"); + } + break; + default: + progress.setVisibility(View.GONE); + mFooterView.setVisibility(View.GONE); + text.setVisibility(View.GONE); + break; } return mFooterView; } @@ -237,7 +246,7 @@ public class ListBaseAdapter extends BaseAdapter { private LinearLayout mFooterView; - protected boolean hasFooterView(){ + protected boolean hasFooterView() { return true; } @@ -295,6 +304,11 @@ public class ListBaseAdapter extends BaseAdapter { } } + + protected void setImageRes(ImageView imageRes, @DrawableRes int resId) { + imageRes.setImageResource(resId); + } + protected void setText(TextView textView, String text) { setText(textView, text, false); } diff --git a/app/src/main/java/net/oschina/app/bean/Banner.java b/app/src/main/java/net/oschina/app/bean/Banner.java new file mode 100644 index 0000000000000000000000000000000000000000..bb601af9b6cf4e63212436c18ae3e80c43368b17 --- /dev/null +++ b/app/src/main/java/net/oschina/app/bean/Banner.java @@ -0,0 +1,78 @@ +package net.oschina.app.bean; + +/** + * Created by huanghaibin + * on 16-5-23. + */ +public class Banner extends Base { + public static final int BANNER_TYPE_URL = 0;//链接新闻 + public static final int BANNER_TYPE_SOFTWARE = 1;// + public static final int BANNER_TYPE_POST = 2;// + public static final int BANNER_TYPE_BLOG = 3;// + public static final int BANNER_TYPE_TRANSLATEL = 4;// + public static final int BANNER_TYPE_EVENT = 5;// + public static final int BANNER_TYPE_NEWS = 6; + private String name; + private String detail; + private String img; + private String href; + private String pubDate; + private int type; + private long id; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDetail() { + return detail; + } + + public void setDetail(String detail) { + this.detail = detail; + } + + public String getImg() { + return img; + } + + public void setImg(String img) { + this.img = img; + } + + public String getHref() { + return href; + } + + public void setHref(String href) { + this.href = href; + } + + public String getPubDate() { + return pubDate; + } + + public void setPubDate(String pubDate) { + this.pubDate = pubDate; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } +} diff --git a/app/src/main/java/net/oschina/app/bean/BarCode.java b/app/src/main/java/net/oschina/app/bean/BarCode.java index c63e5bbb87d212c1cb34956daa9a99c1de30ac83..8a1f76b2d20c035bf8dc30e04c75b704682a117e 100644 --- a/app/src/main/java/net/oschina/app/bean/BarCode.java +++ b/app/src/main/java/net/oschina/app/bean/BarCode.java @@ -1,102 +1,104 @@ package net.oschina.app.bean; -import java.io.Serializable; - import net.oschina.app.AppException; import org.json.JSONException; import org.json.JSONObject; +import java.io.Serializable; + + /** * 二维码扫描实体类 + * * @author 火蚁 (http://my.oschina.net/LittleDY) * @version 1.0 * @created 2014-3-17 */ @SuppressWarnings("serial") -public class BarCode extends Entity implements Serializable{ - - public final static String NODE_REQURE_LOGIN = "require_login"; - public final static String NODE_TYPE = "type"; - public final static String NODE_URL = "url"; - public final static String NODE_TITLE = "title"; - - public final static byte LOGIN_IN = 0x00;// 登录 - public final static byte SIGN_IN = 0x01;// 签到 - - private boolean requireLogin;// 是否需要登录 - private int type;// 类型 - private String url;// url地址 - private String title;// 标题 - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public boolean isRequireLogin() { - return requireLogin; - } - - public void setRequireLogin(boolean requireLogin) { - this.requireLogin = requireLogin; - } - - public int getType() { - return type; - } - - public void setType(int type) { - this.type = type; - } - - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } - - public static BarCode parse(String barCodeString) throws AppException { - BarCode barCode = new BarCode(); - try { - // 由字符串创建json对象 - JSONObject jsonObject = new JSONObject(barCodeString); - // 取数据操作 - if (!jsonObject.isNull(NODE_REQURE_LOGIN)) { - barCode.setRequireLogin(jsonObject.getBoolean(NODE_REQURE_LOGIN)); - } else { - barCode.setUrl("www.oschina.net"); - } - if (!jsonObject.isNull(NODE_TYPE)) { - barCode.setType(jsonObject.getInt(NODE_TYPE)); - } else { - barCode.setType(1); - } - if (!jsonObject.isNull(NODE_URL)) { - barCode.setUrl(jsonObject.getString(NODE_URL)); - } else { - barCode.setUrl("www.oschina.net"); - } - if (!jsonObject.isNull(NODE_TITLE)) { - barCode.setTitle(jsonObject.getString(NODE_TITLE)); - } else { - barCode.setTitle(""); - } - } catch (JSONException e) { - // 抛出一个json解析错误的异常 - throw AppException.json(e); - } - return barCode; - } - - @Override - public String toString() { - return "Barcode [requireLogin=" + requireLogin + ", type=" + type - + ", url=" + url + "]"; - } +public class BarCode extends Entity implements Serializable { + + public final static String NODE_REQURE_LOGIN = "require_login"; + public final static String NODE_TYPE = "type"; + public final static String NODE_URL = "url"; + public final static String NODE_TITLE = "title"; + + public final static byte LOGIN_IN = 0x00;// 登录 + public final static byte SIGN_IN = 0x01;// 签到 + + private boolean requireLogin;// 是否需要登录 + private int type;// 类型 + private String url;// url地址 + private String title;// 标题 + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public boolean isRequireLogin() { + return requireLogin; + } + + public void setRequireLogin(boolean requireLogin) { + this.requireLogin = requireLogin; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public static BarCode parse(String barCodeString) throws AppException { + BarCode barCode = new BarCode(); + try { + // 由字符串创建json对象 + JSONObject jsonObject = new JSONObject(barCodeString); + // 取数据操作 + if (!jsonObject.isNull(NODE_REQURE_LOGIN)) { + barCode.setRequireLogin(jsonObject.getBoolean(NODE_REQURE_LOGIN)); + } else { + barCode.setUrl("www.oschina.net"); + } + if (!jsonObject.isNull(NODE_TYPE)) { + barCode.setType(jsonObject.getInt(NODE_TYPE)); + } else { + barCode.setType(1); + } + if (!jsonObject.isNull(NODE_URL)) { + barCode.setUrl(jsonObject.getString(NODE_URL)); + } else { + barCode.setUrl("www.oschina.net"); + } + if (!jsonObject.isNull(NODE_TITLE)) { + barCode.setTitle(jsonObject.getString(NODE_TITLE)); + } else { + barCode.setTitle(""); + } + } catch (JSONException e) { + // 抛出一个json解析错误的异常 + throw AppException.json(e); + } + return barCode; + } + + @Override + public String toString() { + return "Barcode [requireLogin=" + requireLogin + ", type=" + type + + ", url=" + url + "]"; + } } diff --git a/app/src/main/java/net/oschina/app/bean/BlogDetail.java b/app/src/main/java/net/oschina/app/bean/BlogDetail.java deleted file mode 100644 index 97918d7fc6de7bf15262552c727a93d9b633f066..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/bean/BlogDetail.java +++ /dev/null @@ -1,25 +0,0 @@ -package net.oschina.app.bean; - -import com.thoughtworks.xstream.annotations.XStreamAlias; - -/** - * 博客详情 - * @author FireAnt(http://my.oschina.net/LittleDY) - * @created 2014年10月15日 上午10:51:11 - * - */ -@SuppressWarnings("serial") -@XStreamAlias("oschina") -public class BlogDetail extends Entity { - - @XStreamAlias("blog") - private Blog blog; - - public Blog getBlog() { - return blog; - } - - public void setBlog(Blog blog) { - this.blog = blog; - } -} diff --git a/app/src/main/java/net/oschina/app/bean/FavoriteList.java b/app/src/main/java/net/oschina/app/bean/FavoriteList.java deleted file mode 100644 index 513eb64a430dd331f2a57b4e2b6c90b2de4f0101..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/bean/FavoriteList.java +++ /dev/null @@ -1,50 +0,0 @@ -package net.oschina.app.bean; - -import java.util.ArrayList; -import java.util.List; - -import com.thoughtworks.xstream.annotations.XStreamAlias; - -/** - * 收藏实体类 - * @author FireAnt(http://my.oschina.net/LittleDY) - * @created 2014年10月14日 下午2:27:39 - * - */ -@SuppressWarnings("serial") -@XStreamAlias("oschina") -public class FavoriteList extends Entity implements ListEntity { - - public final static int TYPE_ALL = 0x00; - public final static int TYPE_SOFTWARE = 0x01; - public final static int TYPE_POST = 0x02; - public final static int TYPE_BLOG = 0x03; - public final static int TYPE_NEWS = 0x04; - public final static int TYPE_CODE = 0x05; - - @XStreamAlias("pagesize") - private int pageSize; - @XStreamAlias("favorites") - private List favoritelist = new ArrayList(); - - public int getPageSize() { - return pageSize; - } - - public void setPageSize(int pagesize) { - this.pageSize = pagesize; - } - - public List getFavoritelist() { - return favoritelist; - } - - public void setFavoritelist(List favoritelist) { - this.favoritelist = favoritelist; - } - - @Override - public List getList() { - return favoritelist; - } -} diff --git a/app/src/main/java/net/oschina/app/bean/FindUserList.java b/app/src/main/java/net/oschina/app/bean/FindUserList.java deleted file mode 100644 index 165884e018ef145701c596b562db6c377da34b60..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/bean/FindUserList.java +++ /dev/null @@ -1,37 +0,0 @@ -package net.oschina.app.bean; - -import java.util.ArrayList; -import java.util.List; - -import com.thoughtworks.xstream.annotations.XStreamAlias; - -/** - * 好友实体类 - * - * @author FireAnt(http://my.oschina.net/LittleDY) - * @created 2014年11月6日 上午11:17:36 - * - */ -@SuppressWarnings("serial") -@XStreamAlias("oschina") -public class FindUserList extends Entity implements ListEntity { - - public final static int TYPE_FANS = 0x00; - public final static int TYPE_FOLLOWER = 0x01; - - @XStreamAlias("users") - private List friendlist = new ArrayList(); - - public List getFriendlist() { - return friendlist; - } - - public void setFriendlist(List resultlist) { - this.friendlist = resultlist; - } - - @Override - public List getList() { - return friendlist; - } -} diff --git a/app/src/main/java/net/oschina/app/bean/LoginUserBean.java b/app/src/main/java/net/oschina/app/bean/LoginUserBean.java deleted file mode 100644 index a6d7ac9a4b4252b296f2713a60e3491ce6cb4a38..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/bean/LoginUserBean.java +++ /dev/null @@ -1,37 +0,0 @@ -package net.oschina.app.bean; - -import com.thoughtworks.xstream.annotations.XStreamAlias; - -/** - * @author FireAnt(http://my.oschina.net/LittleDY) - * @version 创建时间:2014年9月27日 下午2:45:57 - * - */ - -@SuppressWarnings("serial") -@XStreamAlias("oschina") -public class LoginUserBean extends Entity { - - @XStreamAlias("result") - private Result result; - - @XStreamAlias("user") - private User user; - - public Result getResult() { - return result; - } - - public void setResult(Result result) { - this.result = result; - } - - public User getUser() { - return user; - } - - public void setUser(User user) { - this.user = user; - } - -} \ No newline at end of file diff --git a/app/src/main/java/net/oschina/app/bean/MessageDetailList.java b/app/src/main/java/net/oschina/app/bean/MessageDetailList.java deleted file mode 100644 index 7684a8dcbbd88ad051b11955f14f7f1c651a917b..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/bean/MessageDetailList.java +++ /dev/null @@ -1,43 +0,0 @@ -package net.oschina.app.bean; - -import com.thoughtworks.xstream.annotations.XStreamAlias; - -import java.util.ArrayList; -import java.util.List; - -/** - * 聊天详细信息实体类 - * @author 铂金小鸟(http://my.oschina.net/fants) - * @Created 2015年9月16日 上午4:20:01 - */ -@SuppressWarnings("serial") -@XStreamAlias("oschina") -public class MessageDetailList extends Entity implements ListEntity { - - @XStreamAlias("allCount") - private int allCount; - - @XStreamAlias("pagesize") - private int pageSize; - - @XStreamAlias("messages") - private List messagelist = new ArrayList(); - - public int getPageSize() { - return pageSize; - } - - public int getMessageCount() { - return allCount; - } - - public List getMessagelist() { - return messagelist; - } - - @Override - public List getList() { - return messagelist; - } - -} diff --git a/app/src/main/java/net/oschina/app/bean/MessageList.java b/app/src/main/java/net/oschina/app/bean/MessageList.java deleted file mode 100644 index 63cb67eb4fddc6f98cf61ac0c0d11448cde479c4..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/bean/MessageList.java +++ /dev/null @@ -1,43 +0,0 @@ -package net.oschina.app.bean; - -import java.util.ArrayList; -import java.util.List; - -import com.thoughtworks.xstream.annotations.XStreamAlias; - -/** - * 留言实体类列表 - * @author FireAnt(http://my.oschina.net/LittleDY) - * @created 2014年10月22日 下午4:38:49 - * - */ -@SuppressWarnings("serial") -@XStreamAlias("oschina") -public class MessageList extends Entity implements ListEntity { - - @XStreamAlias("pagesize") - private int pageSize; - - @XStreamAlias("messageCount") - private int messageCount; - - @XStreamAlias("messages") - private List messagelist = new ArrayList(); - - public int getPageSize() { - return pageSize; - } - - public int getMessageCount() { - return messageCount; - } - - public List getMessagelist() { - return messagelist; - } - - @Override - public List getList() { - return messagelist; - } -} diff --git a/app/src/main/java/net/oschina/app/bean/MyInformation.java b/app/src/main/java/net/oschina/app/bean/MyInformation.java deleted file mode 100644 index 91a2bf214ead1ec8eedd2b12918ec9f5ec21091d..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/bean/MyInformation.java +++ /dev/null @@ -1,26 +0,0 @@ -package net.oschina.app.bean; - -import com.thoughtworks.xstream.annotations.XStreamAlias; - -/** - * 我的资料实体类 - * @author FireAnt(http://my.oschina.net/LittleDY) - * @version 创建时间:2014年10月30日 下午4:08:30 - * - */ - -@SuppressWarnings("serial") -@XStreamAlias("oschina") -public class MyInformation extends Base { - - @XStreamAlias("user") - private User user; - - public User getUser() { - return user; - } - - public void setUser(User user) { - this.user = user; - } -} diff --git a/app/src/main/java/net/oschina/app/bean/NewsDetail.java b/app/src/main/java/net/oschina/app/bean/NewsDetail.java deleted file mode 100644 index ce68418a35935ed38ee4ed3b948141ebaf105b83..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/bean/NewsDetail.java +++ /dev/null @@ -1,25 +0,0 @@ -package net.oschina.app.bean; - -import com.thoughtworks.xstream.annotations.XStreamAlias; - -/** - * 资讯详情 - * @author FireAnt(http://my.oschina.net/LittleDY) - * @version 创建时间:2014年10月11日 下午3:28:33 - * - */ -@SuppressWarnings("serial") -@XStreamAlias("oschina") -public class NewsDetail extends Entity { - - @XStreamAlias("news") - private News news; - - public News getNews() { - return news; - } - - public void setNews(News news) { - this.news = news; - } -} diff --git a/app/src/main/java/net/oschina/app/bean/NoticeDetail.java b/app/src/main/java/net/oschina/app/bean/NoticeDetail.java deleted file mode 100644 index 776fe5fb7128e90447a7e54d5f9956443c84f14f..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/bean/NoticeDetail.java +++ /dev/null @@ -1,27 +0,0 @@ -package net.oschina.app.bean; - -import com.thoughtworks.xstream.annotations.XStreamAlias; - -/** - * 通知实体类 - * @author FireAnt(http://my.oschina.net/LittleDY) - * @version 创建时间:2014年10月27日 下午2:28:42 - * - */ -@SuppressWarnings("serial") -@XStreamAlias("oschina") -public class NoticeDetail extends Base { - - @XStreamAlias("result") - private Result result; - - public Result getResult() { - return result; - } - - public void setResult(Result result) { - this.result = result; - } - - -} diff --git a/app/src/main/java/net/oschina/app/bean/OpenIdCatalog.java b/app/src/main/java/net/oschina/app/bean/OpenIdCatalog.java deleted file mode 100644 index 7d6efe9cb4cb32b2e269c7180ee46dda6bedd8de..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/bean/OpenIdCatalog.java +++ /dev/null @@ -1,12 +0,0 @@ -package net.oschina.app.bean; - -/** - * Created by zhangdeyi on 15/7/22. - */ -public class OpenIdCatalog { - - public static final String QQ = "qq"; - public static final String WEIBO = "weibo"; - public static final String WECHAT = "wechat"; - public static final String GITHUB = "github"; -} diff --git a/app/src/main/java/net/oschina/app/bean/PostDetail.java b/app/src/main/java/net/oschina/app/bean/PostDetail.java deleted file mode 100644 index 017c5bf86dd52ef899f320dd245bcd02a9638195..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/bean/PostDetail.java +++ /dev/null @@ -1,26 +0,0 @@ -package net.oschina.app.bean; - -import com.thoughtworks.xstream.annotations.XStreamAlias; - -/** - * 帖子详情 - * @author FireAnt(http://my.oschina.net/LittleDY) - * @version 创建时间:2014年10月11日 下午3:28:33 - * - */ -@SuppressWarnings("serial") -@XStreamAlias("oschina") -public class PostDetail extends Entity { - - @XStreamAlias("post") - private Post post; - - public Post getPost() { - return post; - } - - public void setPost(Post post) { - this.post = post; - } - -} diff --git a/app/src/main/java/net/oschina/app/bean/Report.java b/app/src/main/java/net/oschina/app/bean/Report.java index 02c7e9ccaeb6fb31008d8793c32f0b66168f6069..4e276341f5fdd584d0fd0dcf3b69dd76d1b41a75 100644 --- a/app/src/main/java/net/oschina/app/bean/Report.java +++ b/app/src/main/java/net/oschina/app/bean/Report.java @@ -2,7 +2,7 @@ package net.oschina.app.bean; /** * 举报实体类 - * + * * @author 火蚁(http://my.oschina.net/LittleDY) * @version 1.0 * @created 2014-02-13 @@ -12,17 +12,17 @@ public class Report extends Entity { public static final byte TYPE_QUESTION = 0x02;// 问题 - private int objId;//需要举报的id + private long objId;//需要举报的id private String url;// 举报的链接地址 private byte objType;// 举报的类型 private int reason;// 原因 private String otherReason;// 其他原因 - public int getObjId() { + public long getObjId() { return objId; } - public void setObjId(int objId) { + public void setObjId(long objId) { this.objId = objId; } diff --git a/app/src/main/java/net/oschina/app/bean/ResultBean.java b/app/src/main/java/net/oschina/app/bean/ResultBean.java index 687c82a5a197ea4e11d2cb6ddd43e0aa0e702d48..5b17eacf31090c6df9d2a4a65296435bab2f4998 100644 --- a/app/src/main/java/net/oschina/app/bean/ResultBean.java +++ b/app/src/main/java/net/oschina/app/bean/ResultBean.java @@ -4,10 +4,10 @@ import com.thoughtworks.xstream.annotations.XStreamAlias; /** * 操作结果实体类 - * + * * @author FireAnt(http://my.oschina.net/LittleDY) * @version 创建时间:2014年10月14日 下午2:59:27 - * + * */ @SuppressWarnings("serial") @XStreamAlias("oschina") @@ -30,35 +30,35 @@ public class ResultBean extends Base { private int relation; public Result getResult() { - return result; + return result; } public void setResult(Result result) { - this.result = result; + this.result = result; } public int getRelation() { - return relation; + return relation; } public void setRelation(int relation) { - this.relation = relation; + this.relation = relation; } public Notice getNotice() { - return notice; + return notice; } public void setNotice(Notice notice) { - this.notice = notice; + this.notice = notice; } public Comment getComment() { - return comment; + return comment; } public void setComment(Comment comment) { - this.comment = comment; + this.comment = comment; } public MessageDetail getMessage() { diff --git a/app/src/main/java/net/oschina/app/bean/SearchList.java b/app/src/main/java/net/oschina/app/bean/SearchList.java deleted file mode 100644 index 4e212dd92d8dd5be3a5b38b074c64d9e9005b3fd..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/bean/SearchList.java +++ /dev/null @@ -1,43 +0,0 @@ -package net.oschina.app.bean; - -import java.util.ArrayList; -import java.util.List; - -import com.thoughtworks.xstream.annotations.XStreamAlias; - -/** - * 搜索实体类 - * - * @author FireAnt(http://my.oschina.net/LittleDY) - * @created 2014年12月5日 上午11:19:44 - * - */ -@SuppressWarnings("serial") -@XStreamAlias("oschina") -public class SearchList extends Entity implements ListEntity { - - public final static String CATALOG_ALL = "all"; - public final static String CATALOG_NEWS = "news"; - public final static String CATALOG_POST = "post"; - public final static String CATALOG_SOFTWARE = "software"; - public final static String CATALOG_BLOG = "blog"; - - @XStreamAlias("pagesize") - private int pageSize; - - @XStreamAlias("results") - private List list = new ArrayList(); - - public int getPageSize() { - return pageSize; - } - - @Override - public List getList() { - return list; - } - - public void setList(List list) { - this.list = list; - } -} diff --git a/app/src/main/java/net/oschina/app/bean/SearchResult.java b/app/src/main/java/net/oschina/app/bean/SearchResult.java deleted file mode 100644 index e414f412cc8bd3dceeaa9ea77eac6b22204b71cb..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/bean/SearchResult.java +++ /dev/null @@ -1,88 +0,0 @@ -package net.oschina.app.bean; - -import com.thoughtworks.xstream.annotations.XStreamAlias; - -/** - * 搜索结果实体类 - */ -@SuppressWarnings("serial") -@XStreamAlias("result") -public class SearchResult extends Entity { - - @XStreamAlias("objid") - private int id; - - @XStreamAlias("type") - private String type; - - @XStreamAlias("title") - private String title; - - @XStreamAlias("description") - private String description; - - @XStreamAlias("url") - private String url; - - @XStreamAlias("pubDate") - private String pubDate; - - @XStreamAlias("author") - private String author; - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } - - public String getPubDate() { - return pubDate; - } - - public void setPubDate(String pubDate) { - this.pubDate = pubDate; - } - - public String getAuthor() { - return author; - } - - public void setAuthor(String author) { - this.author = author; - } -} diff --git a/app/src/main/java/net/oschina/app/bean/ShakeObject.java b/app/src/main/java/net/oschina/app/bean/ShakeObject.java deleted file mode 100644 index 865de1269247c1c048daf715320416613c1721da..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/bean/ShakeObject.java +++ /dev/null @@ -1,113 +0,0 @@ -package net.oschina.app.bean; - -import com.thoughtworks.xstream.annotations.XStreamAlias; - -@XStreamAlias("oschina") -public class ShakeObject { - - @XStreamAlias("randomtype") - private String randomtype; // 数据类型 - @XStreamAlias("id") - private String id; // 数据id - @XStreamAlias("title") - private String title; // 帖子标题 - @XStreamAlias("detail") - private String detail; // 内容 - @XStreamAlias("author") - private String author; // 作者 - @XStreamAlias("authorid") - private String authorid; // 作者id - @XStreamAlias("image") - private String image; // 头像地址 - @XStreamAlias("pubDate") - private String pubDate; // 收录日期 - @XStreamAlias("commentCount") - private String commentCount; - @XStreamAlias("url") - private String url; - - public static final String RANDOMTYPE_NEWS = "1"; - public static final String RANDOMTYPE_BLOG = "2"; - public static final String RANDOMTYPE_SOFTWARE = "3"; - - public String getRandomtype() { - return randomtype; - } - - public void setRandomtype(String randomtype) { - this.randomtype = randomtype; - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getDetail() { - return detail; - } - - public void setDetail(String detail) { - this.detail = detail; - } - - public String getAuthor() { - return author; - } - - public void setAuthor(String author) { - this.author = author; - } - - public String getAuthorid() { - return authorid; - } - - public void setAuthorid(String authorid) { - this.authorid = authorid; - } - - public String getImage() { - return image; - } - - public void setImage(String image) { - this.image = image; - } - - public String getPubDate() { - return pubDate; - } - - public void setPubDate(String pubDate) { - this.pubDate = pubDate; - } - - public String getCommentCount() { - return commentCount; - } - - public void setCommentCount(String commentCount) { - this.commentCount = commentCount; - } - - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } - -} diff --git a/app/src/main/java/net/oschina/app/bean/SimpleBackPage.java b/app/src/main/java/net/oschina/app/bean/SimpleBackPage.java index 7e40b7f95860bac0148e44ddb1cd0b141f4ac102..6331f4df8cd0f0f711ff951d289c3b8e371891ee 100644 --- a/app/src/main/java/net/oschina/app/bean/SimpleBackPage.java +++ b/app/src/main/java/net/oschina/app/bean/SimpleBackPage.java @@ -2,25 +2,16 @@ package net.oschina.app.bean; import net.oschina.app.R; import net.oschina.app.fragment.AboutOSCFragment; -import net.oschina.app.fragment.ActiveFragment; import net.oschina.app.fragment.BrowserFragment; -import net.oschina.app.fragment.CommentFrament; import net.oschina.app.fragment.EventAppliesFragment; import net.oschina.app.fragment.EventFragment; -import net.oschina.app.fragment.FeedBackFragment; -import net.oschina.app.fragment.MessageDetailFragment; -import net.oschina.app.fragment.MyInformationFragment; import net.oschina.app.fragment.MyInformationFragmentDetail; import net.oschina.app.fragment.QuestionTagFragment; import net.oschina.app.fragment.SettingsFragment; -import net.oschina.app.fragment.SettingsNotificationFragment; -import net.oschina.app.fragment.SoftWareTweetsFrament; -import net.oschina.app.fragment.TweetLikeUsersFragment; -import net.oschina.app.fragment.TweetPubFragment; -import net.oschina.app.fragment.TweetRecordFragment; -import net.oschina.app.fragment.TweetsFragment; -import net.oschina.app.fragment.UserBlogFragment; -import net.oschina.app.fragment.UserCenterFragment; +import net.oschina.app.improve.main.subscription.SubFragment; +import net.oschina.app.improve.tweet.fragments.TweetFragment; +import net.oschina.app.improve.user.fragments.UserBlogFragment; +import net.oschina.app.improve.user.fragments.UserQuestionFragment; import net.oschina.app.team.fragment.NoteBookFragment; import net.oschina.app.team.fragment.NoteEditFragment; import net.oschina.app.team.fragment.TeamActiveFragment; @@ -34,68 +25,23 @@ import net.oschina.app.team.viewpagefragment.MyIssuePagerfragment; import net.oschina.app.team.viewpagefragment.TeamDiaryFragment; import net.oschina.app.team.viewpagefragment.TeamIssueViewPageFragment; import net.oschina.app.team.viewpagefragment.TeamProjectViewPagerFragment; -import net.oschina.app.viewpagerfragment.BlogViewPagerFragment; import net.oschina.app.viewpagerfragment.EventViewPagerFragment; -import net.oschina.app.viewpagerfragment.FriendsViewPagerFragment; -import net.oschina.app.viewpagerfragment.NoticeViewPagerFragment; -import net.oschina.app.viewpagerfragment.OpensourceSoftwareFragment; -import net.oschina.app.viewpagerfragment.QuestViewPagerFragment; -import net.oschina.app.viewpagerfragment.SearchViewPageFragment; -import net.oschina.app.viewpagerfragment.UserFavoriteViewPagerFragment; +import net.oschina.app.viewpagerfragment.OpenSoftwareFragment; public enum SimpleBackPage { - COMMENT(1, R.string.actionbar_title_comment, CommentFrament.class), - - QUEST(2, R.string.actionbar_title_questions, QuestViewPagerFragment.class), - - TWEET_PUB(3, R.string.actionbar_title_tweetpub, TweetPubFragment.class), - - SOFTWARE_TWEETS(4, R.string.actionbar_title_softtweet, - SoftWareTweetsFrament.class), - - USER_CENTER(5, R.string.actionbar_title_user_center, - UserCenterFragment.class), - USER_BLOG(6, R.string.actionbar_title_user_blog, UserBlogFragment.class), - MY_INFORMATION(7, R.string.actionbar_title_my_information, - MyInformationFragment.class), - - MY_ACTIVE(8, R.string.actionbar_title_active, ActiveFragment.class), - - MY_MES(9, R.string.actionbar_title_mes, NoticeViewPagerFragment.class), - - OPENSOURCE_SOFTWARE(10, R.string.actionbar_title_softwarelist, - OpensourceSoftwareFragment.class), - - MY_FRIENDS(11, R.string.actionbar_title_my_friends, - FriendsViewPagerFragment.class), + OPEN_SOURCE_SOFTWARE(10, R.string.actionbar_title_softwarelist, + OpenSoftwareFragment.class), QUESTION_TAG(12, R.string.actionbar_title_question, QuestionTagFragment.class), - MESSAGE_DETAIL(13, R.string.actionbar_title_message_detail, - MessageDetailFragment.class), - - USER_FAVORITE(14, R.string.actionbar_title_user_favorite, - UserFavoriteViewPagerFragment.class), - SETTING(15, R.string.actionbar_title_setting, SettingsFragment.class), - SETTING_NOTIFICATION(16, R.string.actionbar_title_setting_notification, - SettingsNotificationFragment.class), - ABOUT_OSC(17, R.string.actionbar_title_about_osc, AboutOSCFragment.class), - BLOG(18, R.string.actionbar_title_blog_area, BlogViewPagerFragment.class), - - RECORD(19, R.string.actionbar_title_tweetpub, TweetRecordFragment.class), - - SEARCH(20, R.string.actionbar_title_search, SearchViewPageFragment.class), - - EVENT_LIST(21, R.string.actionbar_title_event, EventViewPagerFragment.class), - EVENT_APPLY(22, R.string.actionbar_title_event_apply, EventAppliesFragment.class), @@ -112,8 +58,6 @@ public enum SimpleBackPage { MY_INFORMATION_DETAIL(28, R.string.actionbar_title_my_information, MyInformationFragmentDetail.class), - FEED_BACK(29, R.string.str_feedback_title, FeedBackFragment.class), - TEAM_USER_INFO(30, R.string.str_team_userinfo, TeamMemberInformationFragment.class), @@ -137,9 +81,13 @@ public enum SimpleBackPage { TEAM_PROJECT(40, R.string.team_project, TeamProjectFragment.class), - TWEET_LIKE_USER_LIST(41, 0, TweetLikeUsersFragment.class), + TWEET_TOPIC_LIST(42, R.string.topic_list, TweetFragment.class), + + MY_EVENT(43, R.string.actionbar_title_my_event, EventViewPagerFragment.class), + + MY_QUESTION(44, R.string.question, UserQuestionFragment.class), - TWEET_TOPIC_LIST(42, 0, TweetsFragment.class); + OUTLINE_EVENTS(45, R.string.event_type_outline, SubFragment.class); private int title; private Class clz; @@ -182,4 +130,6 @@ public enum SimpleBackPage { } return null; } + + } diff --git a/app/src/main/java/net/oschina/app/bean/Software.java b/app/src/main/java/net/oschina/app/bean/Software.java deleted file mode 100644 index 3564a489fba6e43917d25b4b4be13b8aea0f79a0..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/bean/Software.java +++ /dev/null @@ -1,202 +0,0 @@ -package net.oschina.app.bean; - -import com.thoughtworks.xstream.annotations.XStreamAlias; - -/** - * 软件实体类 - * - * @author FireAnt(http://my.oschina.net/LittleDY) - * @created 2014年10月23日 下午3:03:25 - * - */ -@SuppressWarnings("serial") -@XStreamAlias("software") -public class Software extends Entity { - - @XStreamAlias("title") - private String title; - - @XStreamAlias("author") - private String author; - - @XStreamAlias("authorid") - private int authorId; - - @XStreamAlias("recommended") - private int recommended; - - @XStreamAlias("extensiontitle") - private String extensionTitle; - - @XStreamAlias("license") - private String license; - - @XStreamAlias("body") - private String body; - - @XStreamAlias("homepage") - private String homepage; - - @XStreamAlias("document") - private String document; - - @XStreamAlias("download") - private String download; - - @XStreamAlias("logo") - private String logo; - - @XStreamAlias("language") - private String language; - - @XStreamAlias("os") - private String os; - - @XStreamAlias("recordtime") - private String recordtime; - - @XStreamAlias("url") - private String url; - - @XStreamAlias("favorite") - private int favorite; - - @XStreamAlias("tweetCount") - private int tweetCount; - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getAuthor() { - return author; - } - - public void setAuthor(String author) { - this.author = author; - } - - public int getAuthorId() { - return authorId; - } - - public void setAuthorId(int authorId) { - this.authorId = authorId; - } - - public int getRecommended() { - return recommended; - } - - public void setRecommended(int recommended) { - this.recommended = recommended; - } - - public String getExtensionTitle() { - return extensionTitle; - } - - public void setExtensionTitle(String extensionTitle) { - this.extensionTitle = extensionTitle; - } - - public String getLicense() { - return license; - } - - public void setLicense(String license) { - this.license = license; - } - - public String getBody() { - return body; - } - - public void setBody(String body) { - this.body = body; - } - - public String getHomepage() { - return homepage; - } - - public void setHomepage(String homepage) { - this.homepage = homepage; - } - - public String getDocument() { - return document; - } - - public void setDocument(String document) { - this.document = document; - } - - public String getDownload() { - return download; - } - - public void setDownload(String download) { - this.download = download; - } - - public String getLogo() { - return logo; - } - - public void setLogo(String logo) { - this.logo = logo; - } - - public String getLanguage() { - return language; - } - - public void setLanguage(String language) { - this.language = language; - } - - public String getOs() { - return os; - } - - public void setOs(String os) { - this.os = os; - } - - public String getRecordtime() { - return recordtime; - } - - public void setRecordtime(String recordtime) { - this.recordtime = recordtime; - } - - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } - - public int getFavorite() { - return favorite; - } - - public void setFavorite(int favorite) { - this.favorite = favorite; - } - - public int getTweetCount() { - return tweetCount; - } - - public void setTweetCount(int tweetCount) { - this.tweetCount = tweetCount; - } -} diff --git a/app/src/main/java/net/oschina/app/bean/SoftwareDetail.java b/app/src/main/java/net/oschina/app/bean/SoftwareDetail.java deleted file mode 100644 index b4d7689a18a78b6f71c6bc7b391b09efa65425b5..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/bean/SoftwareDetail.java +++ /dev/null @@ -1,26 +0,0 @@ -package net.oschina.app.bean; - -import com.thoughtworks.xstream.annotations.XStreamAlias; - -/** - * 软件详情实体类 - * - * @author FireAnt(http://my.oschina.net/LittleDY) - * @version 创建时间:2014年10月23日 下午3:10:54 - * - */ -@SuppressWarnings("serial") -@XStreamAlias("oschina") -public class SoftwareDetail extends Entity { - - @XStreamAlias("software") - private Software software; - - public Software getSoftware() { - return software; - } - - public void setSoftware(Software software) { - this.software = software; - } -} diff --git a/app/src/main/java/net/oschina/app/bean/Tweet.java b/app/src/main/java/net/oschina/app/bean/Tweet.java index 38de54d17f46ea5408247b537d4693e7888a253e..f8347874bd04c091ac3afaef3b7edd46757d7980 100644 --- a/app/src/main/java/net/oschina/app/bean/Tweet.java +++ b/app/src/main/java/net/oschina/app/bean/Tweet.java @@ -17,6 +17,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias; import net.oschina.app.AppContext; import net.oschina.app.base.BaseListFragment; +import net.oschina.app.improve.account.AccountHelper; import net.oschina.app.util.UIHelper; import java.util.ArrayList; @@ -85,6 +86,7 @@ public class Tweet extends Entity implements Parcelable { imageFilePath = dest.readString(); audioPath = dest.readString(); isLike = dest.readInt(); + likeCount = dest.readInt(); } public String getAttach() { @@ -228,6 +230,7 @@ public class Tweet extends Entity implements Parcelable { dest.writeString(imageFilePath); dest.writeString(audioPath); dest.writeInt(isLike); + dest.writeInt(likeCount); } public static final Parcelable.Creator CREATOR = new Creator() { @@ -256,6 +259,7 @@ public class Tweet extends Entity implements Parcelable { likeUser.setVisibility(View.GONE); likeUser.setText(""); } + likeUser.setVisibility(View.GONE); } /** @@ -274,12 +278,11 @@ public class Tweet extends Entity implements Parcelable { if (getIsLike() == 1) { for (int i = 0; i < getLikeUser().size(); i++) { - if (getLikeUser().get(i).getId() == AppContext.getInstance() - .getLoginUid()) { + if (getLikeUser().get(i).getId() == AccountHelper.getUserId()) { getLikeUser().remove(i); } } - getLikeUser().add(0, AppContext.getInstance().getLoginUser()); + //getLikeUser().add(0, AccountHelper.getUser()); } for (int i = 0; i < showCunt; i++) { @@ -332,10 +335,7 @@ public class Tweet extends Entity implements Parcelable { @Override public void onClick(View widget) { - Bundle bundle = new Bundle(); - bundle.putInt(BaseListFragment.BUNDLE_KEY_CATALOG, getId()); - UIHelper.showSimpleBack(context, - SimpleBackPage.TWEET_LIKE_USER_LIST, bundle); + } @Override @@ -352,4 +352,5 @@ public class Tweet extends Entity implements Parcelable { return ssb.append("觉得很赞"); } } + } diff --git a/app/src/main/java/net/oschina/app/bean/TweetDetail.java b/app/src/main/java/net/oschina/app/bean/TweetDetail.java deleted file mode 100644 index fbb850a4bc5dbfa486da4645f16fbfa1ac27afc4..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/bean/TweetDetail.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.oschina.app.bean; - -import com.thoughtworks.xstream.annotations.XStreamAlias; - -/** - * @author HuangWenwei - * - * @date 2014年10月16日 - */ -@SuppressWarnings("serial") -@XStreamAlias("oschina") -public class TweetDetail extends Entity { - - @XStreamAlias("tweet") - private Tweet tweet; - - public Tweet getTweet() { - return tweet; - } - public void setTweet(Tweet tweet) { - this.tweet = tweet; - } -} diff --git a/app/src/main/java/net/oschina/app/bean/TweetLike.java b/app/src/main/java/net/oschina/app/bean/TweetLike.java index 2faf97d670d7374ad145ad36e7a0b37e1a70ba1b..2e222c91348073346dab89081afcd3368d1257a9 100644 --- a/app/src/main/java/net/oschina/app/bean/TweetLike.java +++ b/app/src/main/java/net/oschina/app/bean/TweetLike.java @@ -57,5 +57,7 @@ public class TweetLike extends Entity { public void setAppClient(int appClient) { this.appClient = appClient; } + + } diff --git a/app/src/main/java/net/oschina/app/bean/TweetLikeList.java b/app/src/main/java/net/oschina/app/bean/TweetLikeList.java deleted file mode 100644 index aa22120703357cbf9547feb62aa368730d89ee55..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/bean/TweetLikeList.java +++ /dev/null @@ -1,32 +0,0 @@ -package net.oschina.app.bean; - -import java.util.List; - -import com.thoughtworks.xstream.annotations.XStreamAlias; - -/** - * LikeTweetList.java - * - * @author 火蚁(http://my.oschina.net/u/253900) - * - * @data 2015-4-10 上午10:11:48 - */ -@SuppressWarnings("serial") -@XStreamAlias("oschina") -public class TweetLikeList implements ListEntity { - - @XStreamAlias("likeList") - private List list; - - @Override - public List getList() { - // TODO Auto-generated method stub - return list; - } - - public void setList(List list) { - this.list = list; - } - -} - diff --git a/app/src/main/java/net/oschina/app/bean/TweetLikeUserList.java b/app/src/main/java/net/oschina/app/bean/TweetLikeUserList.java deleted file mode 100644 index df3ee1c359d03d14f828f027f31173bda91ff213..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/bean/TweetLikeUserList.java +++ /dev/null @@ -1,30 +0,0 @@ -package net.oschina.app.bean; - -import java.util.ArrayList; -import java.util.List; - -import com.thoughtworks.xstream.annotations.XStreamAlias; - -/** - * TweetLikeUserList.java - * - * @author 火蚁(http://my.oschina.net/u/253900) - * - * @data 2015-3-26 下午4:23:32 - */ -@SuppressWarnings("serial") -@XStreamAlias("oschina") -public class TweetLikeUserList implements ListEntity { - - @XStreamAlias("likeList") - private List list = new ArrayList(); - - public List getList() { - return list; - } - - public void getList(List list) { - this.list = list; - } -} - diff --git a/app/src/main/java/net/oschina/app/bean/TweetsList.java b/app/src/main/java/net/oschina/app/bean/TweetsList.java deleted file mode 100644 index 5e633868cd38a17e4559450c1c90798a773ecb71..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/bean/TweetsList.java +++ /dev/null @@ -1,57 +0,0 @@ -package net.oschina.app.bean; - -import java.util.ArrayList; -import java.util.List; - -import com.thoughtworks.xstream.annotations.XStreamAlias; - -/** - * @author HuangWenwei - * - * @date 2014年10月10日 - */ -@SuppressWarnings("serial") -@XStreamAlias("oschina") -public class TweetsList extends Entity implements ListEntity { - - public final static int CATALOG_LATEST = 0; - public final static int CATALOG_HOT = -1; - public final static int CATALOG_ME = 1; - - @XStreamAlias("tweetcount") - private int tweetCount; - @XStreamAlias("pagesize") - private int pagesize; - @XStreamAlias("tweets") - private List tweetslist = new ArrayList(); - - public int getTweetCount() { - return tweetCount; - } - - public void setTweetCount(int tweetCount) { - this.tweetCount = tweetCount; - } - - public int getPagesize() { - return pagesize; - } - - public void setPagesize(int pagesize) { - this.pagesize = pagesize; - } - - public List getTweetslist() { - return tweetslist; - } - - public void setTweetslist(List tweetslist) { - this.tweetslist = tweetslist; - } - - @Override - public List getList() { - return tweetslist; - } - -} diff --git a/app/src/main/java/net/oschina/app/bean/Update.java b/app/src/main/java/net/oschina/app/bean/Update.java deleted file mode 100644 index bbc0d8d9fb197a3fb8eeb413decf79e46f323e9e..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/bean/Update.java +++ /dev/null @@ -1,146 +0,0 @@ -package net.oschina.app.bean; - -import java.io.Serializable; - -import com.thoughtworks.xstream.annotations.XStreamAlias; - -/** - * 更新实体类 - * @author FireAnt(http://my.oschina.net/LittleDY) - * @version 创建时间:2014年11月10日 下午12:56:27 - * - */ -@SuppressWarnings("serial") -@XStreamAlias("oschina") -public class Update implements Serializable { - - @XStreamAlias("update") - private UpdateBean update; - - public UpdateBean getUpdate() { - return update; - } - - public void setUpdate(UpdateBean update) { - this.update = update; - } - - @XStreamAlias("update") - public class UpdateBean implements Serializable { - @XStreamAlias("wp7") - private String wp7; - @XStreamAlias("ios") - private String ios; - @XStreamAlias("android") - private AndroidBean android; - - public String getWp7() { - return wp7; - } - - public void setWp7(String wp7) { - this.wp7 = wp7; - } - - public String getIos() { - return ios; - } - - public void setIos(String ios) { - this.ios = ios; - } - - public AndroidBean getAndroid() { - return android; - } - - public void setAndroid(AndroidBean android) { - this.android = android; - } - - } - - @XStreamAlias("android") - public class AndroidBean implements Serializable { - @XStreamAlias("versionCode") - private int versionCode; - @XStreamAlias("versionName") - private String versionName; - @XStreamAlias("downloadUrl") - private String downloadUrl; - @XStreamAlias("updateLog") - private String updateLog; - @XStreamAlias("coverUpdate") - private String coverUpdate; - @XStreamAlias("coverStartDate") - private String coverStartDate; - @XStreamAlias("coverEndDate") - private String coverEndDate; - @XStreamAlias("coverURL") - private String coverURL; - - public int getVersionCode() { - return versionCode; - } - - public void setVersionCode(int versionCode) { - this.versionCode = versionCode; - } - - public String getVersionName() { - return versionName; - } - - public void setVersionName(String versionName) { - this.versionName = versionName; - } - - public String getDownloadUrl() { - return downloadUrl; - } - - public void setDownloadUrl(String downloadUrl) { - this.downloadUrl = downloadUrl; - } - - public String getUpdateLog() { - return updateLog; - } - - public void setUpdateLog(String updateLog) { - this.updateLog = updateLog; - } - - public String getCoverUpdate() { - return coverUpdate; - } - - public void setCoverUpdate(String coverUpdate) { - this.coverUpdate = coverUpdate; - } - - public String getCoverStartDate() { - return coverStartDate; - } - - public void setCoverStartDate(String coverStartDate) { - this.coverStartDate = coverStartDate; - } - - public String getCoverEndDate() { - return coverEndDate; - } - - public void setCoverEndDate(String coverEndDate) { - this.coverEndDate = coverEndDate; - } - - public String getCoverURL() { - return coverURL; - } - - public void setCoverURL(String coverURL) { - this.coverURL = coverURL; - } - } -} diff --git a/app/src/main/java/net/oschina/app/bean/User.java b/app/src/main/java/net/oschina/app/bean/User.java index 4df29db296301f93791626a75143787722709994..165f8f560d6316227b83a7953f0e861699e73b6c 100644 --- a/app/src/main/java/net/oschina/app/bean/User.java +++ b/app/src/main/java/net/oschina/app/bean/User.java @@ -16,11 +16,20 @@ public class User extends Entity { public final static int RELATION_ACTION_DELETE = 0x00;// 取消关注 public final static int RELATION_ACTION_ADD = 0x01;// 加关注 + @Deprecated public final static int RELATION_TYPE_BOTH = 0x01;// 双方互为粉丝 + @Deprecated public final static int RELATION_TYPE_FANS_HIM = 0x02;// 你单方面关注他 + @Deprecated public final static int RELATION_TYPE_NULL = 0x03;// 互不关注 + @Deprecated public final static int RELATION_TYPE_FANS_ME = 0x04;// 只有他关注我 + public final static int RELATION_TYPE_APIV2_BOTH = 0x01;// 双方互为粉丝 + public final static int RELATION_TYPE_APIV2_ONLY_FANS_HIM = 0x02;// 你单方面关注他 + public final static int RELATION_TYPE_APIV2_ONLY_FANS_ME = 0x03;// 只有他关注我 + public final static int RELATION_TYPE_APIV2_NULL = 0x04;// 互不关注 + @XStreamAlias("uid") private int id; diff --git a/app/src/main/java/net/oschina/app/bean/UserInformation.java b/app/src/main/java/net/oschina/app/bean/UserInformation.java deleted file mode 100644 index a23f53ef95afafa1fc62b3c7250c8ef54a6d34cf..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/bean/UserInformation.java +++ /dev/null @@ -1,49 +0,0 @@ -package net.oschina.app.bean; - -import java.util.List; - -import com.thoughtworks.xstream.annotations.XStreamAlias; - -/** - * 个人信息专用实体类 - * @author FireAnt(http://my.oschina.net/LittleDY) - * @version 创建时间:2014年10月29日 上午10:53:54 - * - */ -@SuppressWarnings("serial") -@XStreamAlias("oschina") -public class UserInformation extends Base { - - @XStreamAlias("user") - private User user; - - @XStreamAlias("pagesize") - private int pageSize; - - @XStreamAlias("activies") - private List activeList; - - public User getUser() { - return user; - } - - public void setUser(User user) { - this.user = user; - } - - public int getPageSize() { - return pageSize; - } - - public void setPageSize(int pageSize) { - this.pageSize = pageSize; - } - - public List getActiveList() { - return activeList; - } - - public void setActiveList(List activeList) { - this.activeList = activeList; - } -} \ No newline at end of file diff --git a/app/src/main/java/net/oschina/app/broadcast/AlarmReceiver.java b/app/src/main/java/net/oschina/app/broadcast/AlarmReceiver.java deleted file mode 100644 index edc1a16e79a2220379846c0b830093949f685019..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/broadcast/AlarmReceiver.java +++ /dev/null @@ -1,16 +0,0 @@ -package net.oschina.app.broadcast; - -import net.oschina.app.service.NoticeUtils; -import net.oschina.app.util.TLog; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; - -public class AlarmReceiver extends BroadcastReceiver { - - @Override - public void onReceive(Context context, Intent intent) { - TLog.log("onReceive ->net.oschina.app收到定时获取消息"); - NoticeUtils.requestNotice(context); - } -} diff --git a/app/src/main/java/net/oschina/app/cache/CacheManager.java b/app/src/main/java/net/oschina/app/cache/CacheManager.java index 1b9ebec7c7b8a147edfe2e1a4f687b67cf327ba2..dd18477e0f1b506b7cae6c3f6fc13ebb2ec07000 100644 --- a/app/src/main/java/net/oschina/app/cache/CacheManager.java +++ b/app/src/main/java/net/oschina/app/cache/CacheManager.java @@ -1,5 +1,10 @@ package net.oschina.app.cache; +import android.content.Context; + +import net.oschina.app.util.TDevice; +import net.oschina.common.utils.StreamUtil; + import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -10,9 +15,6 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; -import net.oschina.app.util.TDevice; -import android.content.Context; - public class CacheManager { // wifi缓存时间为5分钟 @@ -22,105 +24,99 @@ public class CacheManager { /** * 保存对象 - * + * * @param ser * @param file * @throws IOException */ public static boolean saveObject(Context context, Serializable ser, - String file) { - FileOutputStream fos = null; - ObjectOutputStream oos = null; - try { - fos = context.openFileOutput(file, Context.MODE_PRIVATE); - oos = new ObjectOutputStream(fos); - oos.writeObject(ser); - oos.flush(); - return true; - } catch (Exception e) { - e.printStackTrace(); - return false; - } finally { - try { - oos.close(); - } catch (Exception e) { - } - try { - fos.close(); - } catch (Exception e) { - } - } + String file) { + FileOutputStream fos = null; + ObjectOutputStream oos = null; + try { + fos = context.openFileOutput(file, Context.MODE_PRIVATE); + oos = new ObjectOutputStream(fos); + oos.writeObject(ser); + oos.flush(); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } finally { + StreamUtil.close(fos, oos); + } + } + + public static void deleteObject(Context context, String fileName) { + String filePath = context.getFilesDir().getPath() + "/" + fileName; + File file = new File(filePath); + if (file.exists()) { + file.delete(); + } } /** * 读取对象 - * + * * @param file * @return * @throws IOException */ public static Serializable readObject(Context context, String file) { - if (!isExistDataCache(context, file)) - return null; - FileInputStream fis = null; - ObjectInputStream ois = null; - try { - fis = context.openFileInput(file); - ois = new ObjectInputStream(fis); - return (Serializable) ois.readObject(); - } catch (FileNotFoundException e) { - } catch (Exception e) { - e.printStackTrace(); - // 反序列化失败 - 删除缓存文件 - if (e instanceof InvalidClassException) { - File data = context.getFileStreamPath(file); - data.delete(); - } - } finally { - try { - ois.close(); - } catch (Exception e) { - } - try { - fis.close(); - } catch (Exception e) { - } - } - return null; + if (!isExistDataCache(context, file)) + return null; + FileInputStream fis = null; + ObjectInputStream ois = null; + try { + fis = context.openFileInput(file); + ois = new ObjectInputStream(fis); + return (Serializable) ois.readObject(); + } catch (FileNotFoundException e) { + } catch (Exception e) { + e.printStackTrace(); + // 反序列化失败 - 删除缓存文件 + if (e instanceof InvalidClassException) { + File data = context.getFileStreamPath(file); + data.delete(); + } + } finally { + StreamUtil.close(ois, fis); + } + return null; } /** * 判断缓存是否存在 - * + * * @param cachefile * @return */ public static boolean isExistDataCache(Context context, String cachefile) { - if (context == null) - return false; - boolean exist = false; - File data = context.getFileStreamPath(cachefile); - if (data.exists()) - exist = true; - return exist; + if (context == null) + return false; + boolean exist = false; + File data = context.getFileStreamPath(cachefile); + if (data.exists()) + exist = true; + return exist; } /** * 判断缓存是否已经失效 */ public static boolean isCacheDataFailure(Context context, String cachefile) { - File data = context.getFileStreamPath(cachefile); - if (!data.exists()) { + File data = context.getFileStreamPath(cachefile); + if (!data.exists()) { - return false; - } - long existTime = System.currentTimeMillis() - data.lastModified(); - boolean failure = false; - if (TDevice.getNetworkType() == TDevice.NETTYPE_WIFI) { - failure = existTime > wifi_cache_time ? true : false; - } else { - failure = existTime > other_cache_time ? true : false; - } - return failure; + return false; + } + long existTime = System.currentTimeMillis() - data.lastModified(); + boolean failure = false; + if (TDevice.isWifiOpen()) { + failure = existTime > wifi_cache_time; + } else { + failure = existTime > other_cache_time; + } + return failure; } } diff --git a/app/src/main/java/net/oschina/app/emoji/DisplayRules.java b/app/src/main/java/net/oschina/app/emoji/DisplayRules.java index 90440197b613407cba0184d9483507c2febdd5f1..2bcc34122ad8112c10fd2eec46245c6d0ea05174 100644 --- a/app/src/main/java/net/oschina/app/emoji/DisplayRules.java +++ b/app/src/main/java/net/oschina/app/emoji/DisplayRules.java @@ -15,800 +15,441 @@ */ package net.oschina.app.emoji; +import net.oschina.app.R; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import net.oschina.app.R; - /** * Emoji在手机上的显示规则 - * + * * @author kymjs (http://www.kymjs.com) */ public enum DisplayRules { // 注意:value不能从0开始,因为0会被库自动设置为删除按钮 // int type, int value, int resId, String cls - KJEMOJI0(0, 1, R.drawable.smiley_0, "[微笑]", "[0]"), KJEMOJI1(0, 1, - R.drawable.smiley_1, "[撇嘴]", "[1]"), KJEMOJI2(0, 1, - R.drawable.smiley_2, "[色]", "[2]"), KJEMOJI3(0, 1, - R.drawable.smiley_3, "[发呆]", "[3]"), KJEMOJI4(0, 1, - R.drawable.smiley_4, "[得意]", "[4]"), KJEMOJI5(0, 1, - R.drawable.smiley_5, "[流泪]", "[5]"), KJEMOJI6(0, 1, - R.drawable.smiley_6, "[害羞]", "[6]"), KJEMOJI7(0, 1, - R.drawable.smiley_7, "[闭嘴]", "[7]"), KJEMOJI8(0, 1, - R.drawable.smiley_8, "[睡]", "[8]"), KJEMOJI9(0, 1, - R.drawable.smiley_9, "[大哭]", "[9]"), KJEMOJI10(0, 1, - R.drawable.smiley_10, "[尴尬]", "[10]"), KJEMOJI11(0, 1, - R.drawable.smiley_11, "[发怒]", "[11]"), KJEMOJI12(0, 1, - R.drawable.smiley_12, "调皮", "[12]"), KJEMOJI13(0, 1, - R.drawable.smiley_13, "[呲牙]", "[13]"), KJEMOJI14(0, 1, - R.drawable.smiley_14, "[惊讶]", "[14]"), KJEMOJI15(0, 1, - R.drawable.smiley_15, "[难过]", "[15]"), KJEMOJI16(0, 1, - R.drawable.smiley_16, "[酷]", "[16]"), KJEMOJI17(0, 1, - R.drawable.smiley_17, "[冷汗]", "[17]"), KJEMOJI18(0, 1, - R.drawable.smiley_18, "[抓狂]", "[18]"), KJEMOJI19(0, 1, - R.drawable.smiley_19, "[吐]", "[19]"), KJEMOJI20(0, 1, - R.drawable.smiley_20, "[偷笑]", "[20]"), KJEMOJI21(0, 1, - R.drawable.smiley_21, "[可爱]", "[21]"), KJEMOJI22(0, 1, - R.drawable.smiley_22, "[白眼]", "[22]"), KJEMOJI23(0, 1, - R.drawable.smiley_23, "[傲慢]", "[23]"), KJEMOJI24(0, 1, - R.drawable.smiley_24, "[饥饿]", "[24]"), KJEMOJI25(0, 1, - R.drawable.smiley_25, "[困]", "[25]"), KJEMOJI26(0, 1, - R.drawable.smiley_26, "[惊恐]", "[26]"), KJEMOJI27(0, 1, - R.drawable.smiley_27, "[流汗]", "[27]"), KJEMOJI28(0, 1, - R.drawable.smiley_28, "[憨笑]", "[28]"), KJEMOJI29(0, 1, - R.drawable.smiley_29, "[大兵]", "[29]"), KJEMOJI30(0, 1, - R.drawable.smiley_30, "[奋斗]", "[30]"), KJEMOJI31(0, 1, - R.drawable.smiley_31, "[咒骂]", "[31]"), KJEMOJI32(0, 1, - R.drawable.smiley_32, "[疑问]", "[32]"), KJEMOJI33(0, 1, - R.drawable.smiley_33, "[嘘]", "[33]"), KJEMOJI34(0, 1, - R.drawable.smiley_34, "[晕]", "[34]"), KJEMOJI35(0, 1, - R.drawable.smiley_35, "折磨", "[35]"), KJEMOJI36(0, 1, - R.drawable.smiley_36, "衰", "[36]"), KJEMOJI37(0, 1, - R.drawable.smiley_37, "骷髅", "[37]"), KJEMOJI38(0, 1, - R.drawable.smiley_38, "敲打", "[38]"), KJEMOJI39(0, 1, - R.drawable.smiley_39, "再见", "[39]"), KJEMOJI40(0, 1, - R.drawable.smiley_40, "擦汗", "[40]"), KJEMOJI41(0, 1, - R.drawable.smiley_41, "抠鼻", "[41]"), KJEMOJI42(0, 1, - R.drawable.smiley_42, "鼓掌", "[42]"), KJEMOJI43(0, 1, - R.drawable.smiley_43, "糗大了", "[43]"), KJEMOJI44(0, 1, - R.drawable.smiley_44, "坏笑", "[44]"), KJEMOJI45(0, 1, - R.drawable.smiley_45, "[左哼哼]", "[45]"), KJEMOJI46(0, 1, - R.drawable.smiley_46, "[右哼哼]", "[46]"), KJEMOJI47(0, 1, - R.drawable.smiley_47, "[哈欠]", "[47]"), KJEMOJI48(0, 1, - R.drawable.smiley_48, "[鄙视]", "[48]"), KJEMOJI49(0, 1, - R.drawable.smiley_49, "[委屈]", "[49]"), KJEMOJI50(0, 1, - R.drawable.smiley_50, "[快哭了]", "[50]"), KJEMOJI51(0, 1, - R.drawable.smiley_51, "[阴险]", "[51]"), KJEMOJI52(0, 1, - R.drawable.smiley_52, "[亲亲]", "[52]"), KJEMOJI53(0, 1, - R.drawable.smiley_53, "[吓]", "[53]"), KJEMOJI54(0, 1, - R.drawable.smiley_54, "[可怜]", "[54]"), KJEMOJI55(0, 1, - R.drawable.smiley_55, "[菜刀]", "[55]"), KJEMOJI56(0, 1, - R.drawable.smiley_56, "[西瓜]", "[56]"), KJEMOJI57(0, 1, - R.drawable.smiley_57, "[啤酒]", "[57]"), KJEMOJI58(0, 1, - R.drawable.smiley_58, "[篮球]", "[58]"), KJEMOJI59(0, 1, - R.drawable.smiley_59, "[乒乓]", "[59]"), KJEMOJI60(0, 1, - R.drawable.smiley_60, "[咖啡]", "[60]"), KJEMOJI61(0, 1, - R.drawable.smiley_61, "[饭]", "[61]"), KJEMOJI62(0, 1, - R.drawable.smiley_62, "[猪头]", "[62]"), KJEMOJI63(0, 1, - R.drawable.smiley_63, "[玫瑰]", "[63]"), KJEMOJI64(0, 1, - R.drawable.smiley_64, "[凋谢]", "[64]"), KJEMOJI65(0, 1, - R.drawable.smiley_65, "[嘴唇]", "[65]"), KJEMOJI66(0, 1, - R.drawable.smiley_66, "[爱心]", "[66]"), KJEMOJI67(0, 1, - R.drawable.smiley_67, "[心碎]", "[67]"), KJEMOJI68(0, 1, - R.drawable.smiley_68, "[蛋糕]", "[68]"), KJEMOJI69(0, 1, - R.drawable.smiley_69, "[闪电]", "[69]"), KJEMOJI70(0, 1, - R.drawable.smiley_70, "[炸弹]", "[70]"), KJEMOJI71(0, 1, - R.drawable.smiley_71, "[刀]", "[71]"), KJEMOJI72(0, 1, - R.drawable.smiley_72, "[足球]", "[72]"), KJEMOJI73(0, 1, - R.drawable.smiley_73, "[瓢虫]", "[73]"), KJEMOJI74(0, 1, - R.drawable.smiley_74, "[便便]", "[74]"), KJEMOJI75(0, 1, - R.drawable.smiley_75, "[月亮]", "[75]"), KJEMOJI76(0, 1, - R.drawable.smiley_76, "[太阳]", "[76]"), KJEMOJI77(0, 1, - R.drawable.smiley_77, "[礼物]", "[77]"), KJEMOJI78(0, 1, - R.drawable.smiley_78, "[拥抱]", "[78]"), KJEMOJI79(0, 1, - R.drawable.smiley_79, "[强]", "[79]"), KJEMOJI80(0, 1, - R.drawable.smiley_80, "[弱]", "[80]"), KJEMOJI81(0, 1, - R.drawable.smiley_81, "[握手]", "[81]"), KJEMOJI82(0, 1, - R.drawable.smiley_82, "[胜利]", "[82]"), KJEMOJI83(0, 1, - R.drawable.smiley_83, "[抱拳]", "[83]"), KJEMOJI84(0, 1, - R.drawable.smiley_84, "[勾引]", "[84]"), KJEMOJI85(0, 1, - R.drawable.smiley_85, "[拳头]", "[85]"), KJEMOJI86(0, 1, - R.drawable.smiley_86, "[差劲]", "[86]"), KJEMOJI87(0, 1, - R.drawable.smiley_87, "[爱你]", "[87]"), KJEMOJI88(0, 1, - R.drawable.smiley_88, "[NO]", "[88]"), KJEMOJI89(0, 1, - R.drawable.smiley_89, "[OK]", "[89]"), KJEMOJI90(0, 1, - R.drawable.smiley_90, "[爱情]", "[90]"), KJEMOJI91(0, 1, - R.drawable.smiley_91, "[飞吻]", "[91]"), KJEMOJI92(0, 1, - R.drawable.smiley_92, "[跳跳]", "[92]"), KJEMOJI93(0, 1, - R.drawable.smiley_93, "[发抖]", "[93]"), KJEMOJI94(0, 1, - R.drawable.smiley_94, "[怄火]", "[94]"), KJEMOJI95(0, 1, - R.drawable.smiley_95, "[转圈]", "[95]"), KJEMOJI96(0, 1, - R.drawable.smiley_96, "[磕头]", "[96]"), KJEMOJI97(0, 1, - R.drawable.smiley_97, "[回头]", "[97]"), KJEMOJI98(0, 1, - R.drawable.smiley_98, "[跳绳]", "[98]"), KJEMOJI99(0, 1, - R.drawable.smiley_99, "[投降]", "[99]"), KJEMOJI100(0, 1, - R.drawable.smiley_100, "[激动]", "[100]"), KJEMOJI101(0, 1, - R.drawable.smiley_101, "[乱舞]", "[101]"), KJEMOJI102(0, 1, - R.drawable.smiley_102, "[献吻]", "[102]"), KJEMOJI103(0, 1, - R.drawable.smiley_103, "[左太极]", "[103]"), KJEMOJI104(0, 1, - R.drawable.smiley_104, "[右太极]", "[104]"), - - GITHUB0(1, 1, R.drawable.bowtie, ":bowtie:", ":bowtie:"), - - GITHUB1(1, 1, R.drawable.smile, ":smile:", ":smile:"), - - GITHUB2(1, 1, R.drawable.laughing, ":laughing:", ":laughing:"), - - GITHUB3(1, 1, R.drawable.blush, ":blush:", ":blush:"), - - GITHUB4(1, 1, R.drawable.smiley, ":smiley:", ":smiley:"), - - GITHUB5(1, 1, R.drawable.relaxed, ":relaxed:", ":relaxed:"), - - GITHUB6(1, 1, R.drawable.smirk, ":smirk:", ":smirk:"), - - GITHUB7(1, 1, R.drawable.heart_eyes, ":heart_eyes:", ":heart_eyes:"), - - GITHUB8(1, 1, R.drawable.kissing_heart, ":kissing_heart:", - ":kissing_heart:"), - - GITHUB9(1, 1, R.drawable.kissing_closed_eyes, ":kissing_closed_eyes:", - ":kissing_closed_eyes:"), - - GITHUB10(1, 1, R.drawable.flushed, ":flushed:", ":flushed:"), - - GITHUB11(1, 1, R.drawable.relieved, ":relieved:", ":relieved:"), - - GITHUB12(1, 1, R.drawable.satisfied, ":satisfied:", ":satisfied:"), - - GITHUB13(1, 1, R.drawable.grin, ":grin:", ":grin:"), - - GITHUB14(1, 1, R.drawable.wink, ":wink:", ":wink:"), - - GITHUB15(1, 1, R.drawable.stuck_out_tongue_winking_eye, - ":stuck_out_tongue_winking_eye:", ":stuck_out_tongue_winking_eye:"), - - GITHUB16(1, 1, R.drawable.stuck_out_tongue_closed_eyes, - ":stuck_out_tongue_closed_eyes:", ":stuck_out_tongue_closed_eyes:"), - - GITHUB17(1, 1, R.drawable.grinning, ":grinning:", ":grinning:"), - - GITHUB18(1, 1, R.drawable.kissing, ":kissing:", ":kissing:"), - - GITHUB19(1, 1, R.drawable.kissing_smiling_eyes, ":kissing_smiling_eyes:", - ":kissing_smiling_eyes:"), - - GITHUB20(1, 1, R.drawable.stuck_out_tongue, ":stuck_out_tongue:", - ":stuck_out_tongue:"), - - GITHUB21(1, 1, R.drawable.sleeping, ":sleeping:", ":sleeping:"), - - GITHUB22(1, 1, R.drawable.worried, ":worried:", ":worried:"), - - GITHUB23(1, 1, R.drawable.frowning, ":frowning:", ":frowning:"), - - GITHUB24(1, 1, R.drawable.anguished, ":anguished:", ":anguished:"), - - GITHUB25(1, 1, R.drawable.open_mouth, ":open_mouth:", ":open_mouth:"), - - GITHUB26(1, 1, R.drawable.grimacing, ":grimacing:", ":grimacing:"), - - GITHUB27(1, 1, R.drawable.confused, ":confused:", ":confused:"), - - GITHUB28(1, 1, R.drawable.hushed, ":hushed:", ":hushed:"), - - GITHUB29(1, 1, R.drawable.expressionless, ":expressionless:", - ":expressionless:"), - - GITHUB30(1, 1, R.drawable.unamused, ":unamused:", ":unamused:"), - - GITHUB31(1, 1, R.drawable.sweat_smile, ":sweat_smile:", ":sweat_smile:"), - - GITHUB32(1, 1, R.drawable.sweat, ":sweat:", ":sweat:"), - - GITHUB33(1, 1, R.drawable.disappointed_relieved, ":disappointed_relieved:", - ":disappointed_relieved:"), - - GITHUB34(1, 1, R.drawable.weary, ":weary:", ":weary:"), - - GITHUB35(1, 1, R.drawable.pensive, ":pensive:", ":pensive:"), - - GITHUB36(1, 1, R.drawable.disappointed, ":disappointed:", ":disappointed:"), - - GITHUB37(1, 1, R.drawable.confounded, ":confounded:", ":confounded:"), - - GITHUB38(1, 1, R.drawable.fearful, ":fearful:", ":fearful:"), - - GITHUB39(1, 1, R.drawable.cold_sweat, ":cold_sweat:", ":cold_sweat:"), - - GITHUB40(1, 1, R.drawable.persevere, ":persevere:", ":persevere:"), - - GITHUB41(1, 1, R.drawable.cry, ":cry:", ":cry:"), - - GITHUB42(1, 1, R.drawable.sob, ":sob:", ":sob:"), - - GITHUB43(1, 1, R.drawable.joy, ":joy:", ":joy:"), - - GITHUB44(1, 1, R.drawable.astonished, ":astonished:", ":astonished:"), - - GITHUB45(1, 1, R.drawable.scream, ":scream:", ":scream:"), - - GITHUB46(1, 1, R.drawable.neckbeard, ":neckbeard:", ":neckbeard:"), - - GITHUB47(1, 1, R.drawable.tired_face, ":tired_face:", ":tired_face:"), - - GITHUB48(1, 1, R.drawable.angry, ":angry:", ":angry:"), - - GITHUB49(1, 1, R.drawable.rage, ":rage:", ":rage:"), - - GITHUB50(1, 1, R.drawable.triumph, ":triumph:", ":triumph:"), - - GITHUB51(1, 1, R.drawable.sleepy, ":sleepy:", ":sleepy:"), - - GITHUB52(1, 1, R.drawable.yum, ":yum:", ":yum:"), - - GITHUB53(1, 1, R.drawable.mask, ":mask:", ":mask:"), - - GITHUB54(1, 1, R.drawable.sunglasses, ":sunglasses:", ":sunglasses:"), - - GITHUB55(1, 1, R.drawable.dizzy_face, ":dizzy_face:", ":dizzy_face:"), - - GITHUB56(1, 1, R.drawable.imp, ":imp:", ":imp:"), - - GITHUB57(1, 1, R.drawable.smiling_imp, ":smiling_imp:", ":smiling_imp:"), - - GITHUB58(1, 1, R.drawable.neutral_face, ":neutral_face:", ":neutral_face:"), - - GITHUB59(1, 1, R.drawable.no_mouth, ":no_mouth:", ":no_mouth:"), - - GITHUB60(1, 1, R.drawable.innocent, ":innocent:", ":innocent:"), - - GITHUB61(1, 1, R.drawable.alien, ":alien:", ":alien:"), - - GITHUB62(1, 1, R.drawable.yellow_heart, ":yellow_heart:", ":yellow_heart:"), - - GITHUB63(1, 1, R.drawable.blue_heart, ":blue_heart:", ":blue_heart:"), - - GITHUB64(1, 1, R.drawable.purple_heart, ":purple_heart:", ":purple_heart:"), - - GITHUB65(1, 1, R.drawable.heart, ":heart:", ":heart:"), - - GITHUB66(1, 1, R.drawable.green_heart, ":green_heart:", ":green_heart:"), - - GITHUB67(1, 1, R.drawable.broken_heart, ":broken_heart:", ":broken_heart:"), - - GITHUB68(1, 1, R.drawable.heartbeat, ":heartbeat:", ":heartbeat:"), - - GITHUB69(1, 1, R.drawable.heartpulse, ":heartpulse:", ":heartpulse:"), - - GITHUB70(1, 1, R.drawable.two_hearts, ":two_hearts:", ":two_hearts:"), - - GITHUB71(1, 1, R.drawable.revolving_hearts, ":revolving_hearts:", - ":revolving_hearts:"), - - GITHUB72(1, 1, R.drawable.cupid, ":cupid:", ":cupid:"), - - GITHUB73(1, 1, R.drawable.sparkling_heart, ":sparkling_heart:", - ":sparkling_heart:"), - - GITHUB74(1, 1, R.drawable.sparkles, ":sparkles:", ":sparkles:"), - - GITHUB75(1, 1, R.drawable.star, ":star:", ":star:"), - - GITHUB76(1, 1, R.drawable.star2, ":star2:", ":star2:"), - - GITHUB77(1, 1, R.drawable.dizzy, ":dizzy:", ":dizzy:"), - - GITHUB78(1, 1, R.drawable.boom, ":boom:", ":boom:"), - - GITHUB79(1, 1, R.drawable.collision, ":collision:", ":collision:"), - - GITHUB80(1, 1, R.drawable.anger, ":anger:", ":anger:"), - - GITHUB81(1, 1, R.drawable.exclamation, ":exclamation:", ":exclamation:"), - - GITHUB82(1, 1, R.drawable.question, ":question:", ":question:"), - - GITHUB83(1, 1, R.drawable.grey_exclamation, ":grey_exclamation:", - ":grey_exclamation:"), - - GITHUB84(1, 1, R.drawable.grey_question, ":grey_question:", - ":grey_question:"), - - GITHUB85(1, 1, R.drawable.zzz, ":zzz:", ":zzz:"), - - GITHUB86(1, 1, R.drawable.dash, ":dash:", ":dash:"), - - GITHUB87(1, 1, R.drawable.sweat_drops, ":sweat_drops:", ":sweat_drops:"), - - GITHUB88(1, 1, R.drawable.notes, ":notes:", ":notes:"), - - GITHUB89(1, 1, R.drawable.musical_note, ":musical_note:", ":musical_note:"), - - GITHUB90(1, 1, R.drawable.fire, ":fire:", ":fire:"), - - GITHUB91(1, 1, R.drawable.hankey, ":hankey:", ":hankey:"), - - GITHUB92(1, 1, R.drawable.poop, ":poop:", ":poop:"), - - GITHUB93(1, 1, R.drawable.shit, ":shit:", ":shit:"), - - GITHUB94(1, 1, R.drawable.thumbsup, ":+1:", ":+1:"), - - GITHUB95(1, 1, R.drawable.thumbsup, ":thumbsup:", ":thumbsup:"), - - GITHUB96(1, 1, R.drawable.the_1, ":-1:", ":-1:"), - - GITHUB97(1, 1, R.drawable.thumbsdown, ":thumbsdown:", ":thumbsdown:"), - - GITHUB98(1, 1, R.drawable.ok_hand, ":ok_hand:", ":ok_hand:"), - - GITHUB99(1, 1, R.drawable.punch, ":punch:", ":punch:"), - - GITHUB100(1, 1, R.drawable.facepunch, ":facepunch:", ":facepunch:"), - - GITHUB101(1, 1, R.drawable.fist, ":fist:", ":fist:"), - - GITHUB102(1, 1, R.drawable.v, ":v:", ":v:"), - - GITHUB103(1, 1, R.drawable.wave, ":wave:", ":wave:"), - - GITHUB104(1, 1, R.drawable.hand, ":hand:", ":hand:"), - - GITHUB105(1, 1, R.drawable.raised_hand, ":raised_hand:", ":raised_hand:"), - - GITHUB106(1, 1, R.drawable.open_hands, ":open_hands:", ":open_hands:"), - - GITHUB107(1, 1, R.drawable.point_up, ":point_up:", ":point_up:"), - - GITHUB108(1, 1, R.drawable.point_down, ":point_down:", ":point_down:"), - - GITHUB109(1, 1, R.drawable.point_left, ":point_left:", ":point_left:"), - - GITHUB110(1, 1, R.drawable.point_right, ":point_right:", ":point_right:"), - - GITHUB111(1, 1, R.drawable.raised_hands, ":raised_hands:", ":raised_hands:"), - - GITHUB112(1, 1, R.drawable.pray, ":pray:", ":pray:"), - - GITHUB113(1, 1, R.drawable.point_up_2, ":point_up_2:", ":point_up_2:"), - - GITHUB114(1, 1, R.drawable.clap, ":clap:", ":clap:"), - - GITHUB115(1, 1, R.drawable.muscle, ":muscle:", ":muscle:"), - - GITHUB116(1, 1, R.drawable.metal, ":metal:", ":metal:"), - - GITHUB117(1, 1, R.drawable.fu, ":fu:", ":fu:"), - - GITHUB118(1, 1, R.drawable.walking, ":walking:", ":walking:"), - - GITHUB119(1, 1, R.drawable.runner, ":runner:", ":runner:"), - - GITHUB120(1, 1, R.drawable.running, ":running:", ":running:"), - - GITHUB121(1, 1, R.drawable.couple, ":couple:", ":couple:"), - - GITHUB122(1, 1, R.drawable.family, ":family:", ":family:"), - - GITHUB123(1, 1, R.drawable.two_men_holding_hands, - ":two_men_holding_hands:", ":two_men_holding_hands:"), - - GITHUB124(1, 1, R.drawable.two_women_holding_hands, - ":two_women_holding_hands:", ":two_women_holding_hands:"), - - GITHUB125(1, 1, R.drawable.dancer, ":dancer:", ":dancer:"), - - GITHUB126(1, 1, R.drawable.dancers, ":dancers:", ":dancers:"), - - GITHUB127(1, 1, R.drawable.ok_woman, ":ok_woman:", ":ok_woman:"), - - GITHUB128(1, 1, R.drawable.no_good, ":no_good:", ":no_good:"), - - GITHUB129(1, 1, R.drawable.information_desk_person, - ":information_desk_person:", ":information_desk_person:"), - - GITHUB130(1, 1, R.drawable.raising_hand, ":raising_hand:", ":raising_hand:"), - - GITHUB131(1, 1, R.drawable.bride_with_veil, ":bride_with_veil:", - ":bride_with_veil:"), - - GITHUB132(1, 1, R.drawable.person_with_pouting_face, - ":person_with_pouting_face:", ":person_with_pouting_face:"), - - GITHUB133(1, 1, R.drawable.person_frowning, ":person_frowning:", - ":person_frowning:"), - - GITHUB134(1, 1, R.drawable.bow, ":bow:", ":bow:"), - - GITHUB135(1, 1, R.drawable.couplekiss, ":couplekiss:", ":couplekiss:"), - - GITHUB136(1, 1, R.drawable.couple_with_heart, ":couple_with_heart:", - ":couple_with_heart:"), - - GITHUB137(1, 1, R.drawable.massage, ":massage:", ":massage:"), - - GITHUB138(1, 1, R.drawable.haircut, ":haircut:", ":haircut:"), - - GITHUB139(1, 1, R.drawable.nail_care, ":nail_care:", ":nail_care:"), - - GITHUB140(1, 1, R.drawable.boy, ":boy:", ":boy:"), - - GITHUB141(1, 1, R.drawable.girl, ":girl:", ":girl:"), - - GITHUB142(1, 1, R.drawable.woman, ":woman:", ":woman:"), - - GITHUB143(1, 1, R.drawable.man, ":man:", ":man:"), - - GITHUB144(1, 1, R.drawable.baby, ":baby:", ":baby:"), - - GITHUB145(1, 1, R.drawable.older_woman, ":older_woman:", ":older_woman:"), - - GITHUB146(1, 1, R.drawable.older_man, ":older_man:", ":older_man:"), - - GITHUB147(1, 1, R.drawable.person_with_blond_hair, - ":person_with_blond_hair:", ":person_with_blond_hair:"), - - GITHUB148(1, 1, R.drawable.man_with_gua_pi_mao, ":man_with_gua_pi_mao:", - ":man_with_gua_pi_mao:"), - - GITHUB149(1, 1, R.drawable.man_with_turban, ":man_with_turban:", - ":man_with_turban:"), - - GITHUB150(1, 1, R.drawable.construction_worker, ":construction_worker:", - ":construction_worker:"), - - GITHUB151(1, 1, R.drawable.cop, ":cop:", ":cop:"), - - GITHUB152(1, 1, R.drawable.angel, ":angel:", ":angel:"), - - GITHUB153(1, 1, R.drawable.princess, ":princess:", ":princess:"), - - GITHUB154(1, 1, R.drawable.smiley_cat, ":smiley_cat:", ":smiley_cat:"), - - GITHUB155(1, 1, R.drawable.smile_cat, ":smile_cat:", ":smile_cat:"), - - GITHUB156(1, 1, R.drawable.heart_eyes_cat, ":heart_eyes_cat:", - ":heart_eyes_cat:"), - - GITHUB157(1, 1, R.drawable.kissing_cat, ":kissing_cat:", ":kissing_cat:"), - - GITHUB158(1, 1, R.drawable.smirk_cat, ":smirk_cat:", ":smirk_cat:"), - - GITHUB159(1, 1, R.drawable.scream_cat, ":scream_cat:", ":scream_cat:"), - - GITHUB160(1, 1, R.drawable.crying_cat_face, ":crying_cat_face:", - ":crying_cat_face:"), - - GITHUB161(1, 1, R.drawable.joy_cat, ":joy_cat:", ":joy_cat:"), - - GITHUB162(1, 1, R.drawable.pouting_cat, ":pouting_cat:", ":pouting_cat:"), - - GITHUB163(1, 1, R.drawable.japanese_ogre, ":japanese_ogre:", - ":japanese_ogre:"), - - GITHUB164(1, 1, R.drawable.japanese_goblin, ":japanese_goblin:", - ":japanese_goblin:"), - - GITHUB165(1, 1, R.drawable.see_no_evil, ":see_no_evil:", ":see_no_evil:"), - - GITHUB166(1, 1, R.drawable.hear_no_evil, ":hear_no_evil:", ":hear_no_evil:"), - - GITHUB167(1, 1, R.drawable.speak_no_evil, ":speak_no_evil:", - ":speak_no_evil:"), - - GITHUB168(1, 1, R.drawable.guardsman, ":guardsman:", ":guardsman:"), - - GITHUB169(1, 1, R.drawable.skull, ":skull:", ":skull:"), - - GITHUB170(1, 1, R.drawable.feet, ":feet:", ":feet:"), - - GITHUB171(1, 1, R.drawable.lips, ":lips:", ":lips:"), - - GITHUB172(1, 1, R.drawable.kiss, ":kiss:", ":kiss:"), - - GITHUB173(1, 1, R.drawable.droplet, ":droplet:", ":droplet:"), - - GITHUB174(1, 1, R.drawable.ear, ":ear:", ":ear:"), - - GITHUB175(1, 1, R.drawable.eyes, ":eyes:", ":eyes:"), - - GITHUB176(1, 1, R.drawable.nose, ":nose:", ":nose:"), - - GITHUB177(1, 1, R.drawable.tongue, ":tongue:", ":tongue:"), - - GITHUB178(1, 1, R.drawable.love_letter, ":love_letter:", ":love_letter:"), - - GITHUB179(1, 1, R.drawable.bust_in_silhouette, ":bust_in_silhouette:", - ":bust_in_silhouette:"), - - GITHUB180(1, 1, R.drawable.busts_in_silhouette, ":busts_in_silhouette:", - ":busts_in_silhouette:"), - - GITHUB181(1, 1, R.drawable.speech_balloon, ":speech_balloon:", - ":speech_balloon:"), - - GITHUB182(1, 1, R.drawable.thought_balloon, ":thought_balloon:", - ":thought_balloon:"), - - GITHUB183(1, 1, R.drawable.feelsgood, ":feelsgood:", ":feelsgood:"), - - GITHUB184(1, 1, R.drawable.finnadie, ":finnadie:", ":finnadie:"), - - GITHUB185(1, 1, R.drawable.goberserk, ":goberserk:", ":goberserk:"), - - GITHUB186(1, 1, R.drawable.godmode, ":godmode:", ":godmode:"), - - GITHUB187(1, 1, R.drawable.hurtrealbad, ":hurtrealbad:", ":hurtrealbad:"), - - GITHUB188(1, 1, R.drawable.rage1, ":rage1:", ":rage1:"), - - GITHUB189(1, 1, R.drawable.rage2, ":rage2:", ":rage2:"), - - GITHUB190(1, 1, R.drawable.rage3, ":rage3:", ":rage3:"), - - GITHUB191(1, 1, R.drawable.rage4, ":rage4:", ":rage4:"), - - GITHUB192(1, 1, R.drawable.suspect, ":suspect:", ":suspect:"), - - GITHUB193(1, 1, R.drawable.trollface, ":trollface:", ":trollface:"), - - Nature0(2, 1, R.drawable.sunny, ":sunny:", ":sunny:"), - - Nature1(2, 1, R.drawable.umbrella, ":umbrella:", ":umbrella:"), - - Nature2(2, 1, R.drawable.cloud, ":cloud:", ":cloud:"), - - Nature3(2, 1, R.drawable.snowflake, ":snowflake:", ":snowflake:"), - - Nature4(2, 1, R.drawable.snowman, ":snowman:", ":snowman:"), - - Nature5(2, 1, R.drawable.zap, ":zap:", ":zap:"), - - Nature6(2, 1, R.drawable.cyclone, ":cyclone:", ":cyclone:"), - - Nature7(2, 1, R.drawable.foggy, ":foggy:", ":foggy:"), - - Nature8(2, 1, R.drawable.ocean, ":ocean:", ":ocean:"), - - Nature9(2, 1, R.drawable.cat, ":cat:", ":cat:"), - - Nature10(2, 1, R.drawable.dog, ":dog:", ":dog:"), - - Nature11(2, 1, R.drawable.mouse, ":mouse:", ":mouse:"), - - Nature12(2, 1, R.drawable.hamster, ":hamster:", ":hamster:"), - - Nature13(2, 1, R.drawable.rabbit, ":rabbit:", ":rabbit:"), - - Nature14(2, 1, R.drawable.wolf, ":wolf:", ":wolf:"), - - Nature15(2, 1, R.drawable.frog, ":frog:", ":frog:"), - - Nature16(2, 1, R.drawable.tiger, ":tiger:", ":tiger:"), - - Nature17(2, 1, R.drawable.koala, ":koala:", ":koala:"), - - Nature18(2, 1, R.drawable.bear, ":bear:", ":bear:"), - - Nature19(2, 1, R.drawable.pig, ":pig:", ":pig:"), - - Nature20(2, 1, R.drawable.pig_nose, ":pig_nose:", ":pig_nose:"), - - Nature21(2, 1, R.drawable.cow, ":cow:", ":cow:"), - - Nature22(2, 1, R.drawable.boar, ":boar:", ":boar:"), - - Nature23(2, 1, R.drawable.monkey_face, ":monkey_face:", ":monkey_face:"), - - Nature24(2, 1, R.drawable.monkey, ":monkey:", ":monkey:"), - - Nature25(2, 1, R.drawable.horse, ":horse:", ":horse:"), - - Nature26(2, 1, R.drawable.racehorse, ":racehorse:", ":racehorse:"), - - Nature27(2, 1, R.drawable.camel, ":camel:", ":camel:"), - - Nature28(2, 1, R.drawable.sheep, ":sheep:", ":sheep:"), - - Nature29(2, 1, R.drawable.elephant, ":elephant:", ":elephant:"), - - Nature30(2, 1, R.drawable.panda_face, ":panda_face:", ":panda_face:"), - - Nature31(2, 1, R.drawable.snake, ":snake:", ":snake:"), - - Nature32(2, 1, R.drawable.bird, ":bird:", ":bird:"), - - Nature33(2, 1, R.drawable.baby_chick, ":baby_chick:", ":baby_chick:"), - - Nature34(2, 1, R.drawable.hatched_chick, ":hatched_chick:", - ":hatched_chick:"), - - Nature35(2, 1, R.drawable.hatching_chick, ":hatching_chick:", - ":hatching_chick:"), - - Nature36(2, 1, R.drawable.chicken, ":chicken:", ":chicken:"), - - Nature37(2, 1, R.drawable.penguin, ":penguin:", ":penguin:"), - - Nature38(2, 1, R.drawable.turtle, ":turtle:", ":turtle:"), - - Nature39(2, 1, R.drawable.bug, ":bug:", ":bug:"), - - Nature40(2, 1, R.drawable.honeybee, ":honeybee:", ":honeybee:"), - - Nature41(2, 1, R.drawable.ant, ":ant:", ":ant:"), - - Nature42(2, 1, R.drawable.beetle, ":beetle:", ":beetle:"), - - Nature43(2, 1, R.drawable.snail, ":snail:", ":snail:"), - - Nature44(2, 1, R.drawable.octopus, ":octopus:", ":octopus:"), - - Nature45(2, 1, R.drawable.tropical_fish, ":tropical_fish:", - ":tropical_fish:"), - - Nature46(2, 1, R.drawable.fish, ":fish:", ":fish:"), - - Nature47(2, 1, R.drawable.whale, ":whale:", ":whale:"), - - Nature48(2, 1, R.drawable.whale2, ":whale2:", ":whale2:"), - - Nature49(2, 1, R.drawable.dolphin, ":dolphin:", ":dolphin:"), - - Nature50(2, 1, R.drawable.cow2, ":cow2:", ":cow2:"), - - Nature51(2, 1, R.drawable.ram, ":ram:", ":ram:"), - - Nature52(2, 1, R.drawable.rat, ":rat:", ":rat:"), - - Nature53(2, 1, R.drawable.water_buffalo, ":water_buffalo:", - ":water_buffalo:"), - - Nature54(2, 1, R.drawable.tiger2, ":tiger2:", ":tiger2:"), - - Nature55(2, 1, R.drawable.rabbit2, ":rabbit2:", ":rabbit2:"), - - Nature56(2, 1, R.drawable.dragon, ":dragon:", ":dragon:"), - - Nature57(2, 1, R.drawable.goat, ":goat:", ":goat:"), - - Nature58(2, 1, R.drawable.rooster, ":rooster:", ":rooster:"), - - Nature59(2, 1, R.drawable.dog2, ":dog2:", ":dog2:"), - - Nature60(2, 1, R.drawable.pig2, ":pig2:", ":pig2:"), - - Nature61(2, 1, R.drawable.mouse2, ":mouse2:", ":mouse2:"), - - Nature62(2, 1, R.drawable.ox, ":ox:", ":ox:"), - - Nature63(2, 1, R.drawable.dragon_face, ":dragon_face:", ":dragon_face:"), - - Nature64(2, 1, R.drawable.blowfish, ":blowfish:", ":blowfish:"), - - Nature65(2, 1, R.drawable.crocodile, ":crocodile:", ":crocodile:"), - - Nature66(2, 1, R.drawable.dromedary_camel, ":dromedary_camel:", - ":dromedary_camel:"), - - Nature67(2, 1, R.drawable.leopard, ":leopard:", ":leopard:"), - - Nature68(2, 1, R.drawable.cat2, ":cat2:", ":cat2:"), - - Nature69(2, 1, R.drawable.poodle, ":poodle:", ":poodle:"), - - Nature70(2, 1, R.drawable.paw_prints, ":paw_prints:", ":paw_prints:"), - - Nature71(2, 1, R.drawable.bouquet, ":bouquet:", ":bouquet:"), - - Nature72(2, 1, R.drawable.cherry_blossom, ":cherry_blossom:", - ":cherry_blossom:"), - - Nature73(2, 1, R.drawable.tulip, ":tulip:", ":tulip:"), - - Nature74(2, 1, R.drawable.four_leaf_clover, ":four_leaf_clover:", - ":four_leaf_clover:"), - - Nature75(2, 1, R.drawable.rose, ":rose:", ":rose:"), - - Nature76(2, 1, R.drawable.sunflower, ":sunflower:", ":sunflower:"), - - Nature77(2, 1, R.drawable.hibiscus, ":hibiscus:", ":hibiscus:"), - - Nature78(2, 1, R.drawable.maple_leaf, ":maple_leaf:", ":maple_leaf:"), - - Nature79(2, 1, R.drawable.leaves, ":leaves:", ":leaves:"), - - Nature80(2, 1, R.drawable.fallen_leaf, ":fallen_leaf:", ":fallen_leaf:"), - - Nature81(2, 1, R.drawable.herb, ":herb:", ":herb:"), - - Nature82(2, 1, R.drawable.mushroom, ":mushroom:", ":mushroom:"), - - Nature83(2, 1, R.drawable.cactus, ":cactus:", ":cactus:"), - - Nature84(2, 1, R.drawable.palm_tree, ":palm_tree:", ":palm_tree:"), - - Nature85(2, 1, R.drawable.evergreen_tree, ":evergreen_tree:", - ":evergreen_tree:"), - - Nature86(2, 1, R.drawable.deciduous_tree, ":deciduous_tree:", - ":deciduous_tree:"), - - Nature87(2, 1, R.drawable.chestnut, ":chestnut:", ":chestnut:"), - - Nature88(2, 1, R.drawable.seedling, ":seedling:", ":seedling:"), - - Nature89(2, 1, R.drawable.blossom, ":blossom:", ":blossom:"), - - Nature90(2, 1, R.drawable.ear_of_rice, ":ear_of_rice:", ":ear_of_rice:"), - - Nature91(2, 1, R.drawable.shell, ":shell:", ":shell:"), - - Nature92(2, 1, R.drawable.globe_with_meridians, ":globe_with_meridians:", - ":globe_with_meridians:"), - - Nature93(2, 1, R.drawable.sun_with_face, ":sun_with_face:", - ":sun_with_face:"), - - Nature94(2, 1, R.drawable.full_moon_with_face, ":full_moon_with_face:", - ":full_moon_with_face:"), - - Nature95(2, 1, R.drawable.new_moon_with_face, ":new_moon_with_face:", - ":new_moon_with_face:"), - - Nature96(2, 1, R.drawable.new_moon, ":new_moon:", ":new_moon:"), - - Nature97(2, 1, R.drawable.waxing_crescent_moon, ":waxing_crescent_moon:", - ":waxing_crescent_moon:"), - - Nature98(2, 1, R.drawable.first_quarter_moon, ":first_quarter_moon:", - ":first_quarter_moon:"), - - Nature99(2, 1, R.drawable.waxing_gibbous_moon, ":waxing_gibbous_moon:", - ":waxing_gibbous_moon:"), - - Nature100(2, 1, R.drawable.full_moon, ":full_moon:", ":full_moon:"), - - Nature101(2, 1, R.drawable.waning_gibbous_moon, ":waning_gibbous_moon:", - ":waning_gibbous_moon:"), - - Nature102(2, 1, R.drawable.last_quarter_moon, ":last_quarter_moon:", - ":last_quarter_moon:"), - - Nature103(2, 1, R.drawable.waning_crescent_moon, ":waning_crescent_moon:", - ":waning_crescent_moon:"), - - Nature104(2, 1, R.drawable.last_quarter_moon_with_face, - ":last_quarter_moon_with_face:", ":last_quarter_moon_with_face:"), - - Nature105(2, 1, R.drawable.first_quarter_moon_with_face, - ":first_quarter_moon_with_face:", ":first_quarter_moon_with_face:"), - - Nature106(2, 1, R.drawable.moon, ":moon:", ":moon:"), - - Nature107(2, 1, R.drawable.earth_africa, ":earth_africa:", ":earth_africa:"), - - Nature108(2, 1, R.drawable.earth_americas, ":earth_americas:", - ":earth_americas:"), - - Nature109(2, 1, R.drawable.earth_asia, ":earth_asia:", ":earth_asia:"), - - Nature110(2, 1, R.drawable.volcano, ":volcano:", ":volcano:"), - - Nature111(2, 1, R.drawable.milky_way, ":milky_way:", ":milky_way:"), - - Nature112(2, 1, R.drawable.partly_sunny, ":partly_sunny:", ":partly_sunny:"), - - Nature113(2, 1, R.drawable.octocat, ":octocat:", ":octocat:"), - - Nature114(2, 1, R.drawable.squirrel, ":squirrel:", ":squirrel:"); - - /********************************* 操作 **************************************/ + KJEMOJI0(0, 1, R.mipmap.smiley_0, "[微笑]", "[0]"), + KJEMOJI1(0, 1, R.mipmap.smiley_1, "[撇嘴]", "[1]"), + KJEMOJI2(0, 1, R.mipmap.smiley_2, "[色]", "[2]"), + KJEMOJI3(0, 1, R.mipmap.smiley_3, "[发呆]", "[3]"), + KJEMOJI4(0, 1, R.mipmap.smiley_4, "[得意]", "[4]"), + KJEMOJI5(0, 1, R.mipmap.smiley_5, "[流泪]", "[5]"), + KJEMOJI6(0, 1, R.mipmap.smiley_6, "[害羞]", "[6]"), + KJEMOJI7(0, 1, R.mipmap.smiley_7, "[闭嘴]", "[7]"), + KJEMOJI8(0, 1, R.mipmap.smiley_8, "[睡]", "[8]"), + KJEMOJI9(0, 1, R.mipmap.smiley_9, "[大哭]", "[9]"), + KJEMOJI10(0, 1, R.mipmap.smiley_10, "[尴尬]", "[10]"), + KJEMOJI11(0, 1, R.mipmap.smiley_11, "[发怒]", "[11]"), + KJEMOJI12(0, 1, R.mipmap.smiley_12, "[调皮]", "[12]"), + KJEMOJI13(0, 1, R.mipmap.smiley_13, "[呲牙]", "[13]"), + KJEMOJI14(0, 1, R.mipmap.smiley_14, "[惊讶]", "[14]"), + KJEMOJI15(0, 1, R.mipmap.smiley_15, "[难过]", "[15]"), + KJEMOJI16(0, 1, R.mipmap.smiley_16, "[酷]", "[16]"), + KJEMOJI17(0, 1, R.mipmap.smiley_17, "[冷汗]", "[17]"), + KJEMOJI18(0, 1, R.mipmap.smiley_18, "[抓狂]", "[18]"), + KJEMOJI19(0, 1, R.mipmap.smiley_19, "[吐]", "[19]"), + KJEMOJI20(0, 1, R.mipmap.smiley_20, "[偷笑]", "[20]"), + KJEMOJI21(0, 1, R.mipmap.smiley_21, "[可爱]", "[21]"), + KJEMOJI22(0, 1, R.mipmap.smiley_22, "[白眼]", "[22]"), + KJEMOJI23(0, 1, R.mipmap.smiley_23, "[傲慢]", "[23]"), + KJEMOJI24(0, 1, R.mipmap.smiley_24, "[饥饿]", "[24]"), + KJEMOJI25(0, 1, R.mipmap.smiley_25, "[困]", "[25]"), + KJEMOJI26(0, 1, R.mipmap.smiley_26, "[惊恐]", "[26]"), + KJEMOJI27(0, 1, R.mipmap.smiley_27, "[流汗]", "[27]"), + KJEMOJI28(0, 1, R.mipmap.smiley_28, "[憨笑]", "[28]"), + KJEMOJI29(0, 1, R.mipmap.smiley_29, "[大兵]", "[29]"), + KJEMOJI30(0, 1, R.mipmap.smiley_30, "[奋斗]", "[30]"), + KJEMOJI31(0, 1, R.mipmap.smiley_31, "[咒骂]", "[31]"), + KJEMOJI32(0, 1, R.mipmap.smiley_32, "[疑问]", "[32]"), + KJEMOJI33(0, 1, R.mipmap.smiley_33, "[嘘]", "[33]"), + KJEMOJI34(0, 1, R.mipmap.smiley_34, "[晕]", "[34]"), + KJEMOJI35(0, 1, R.mipmap.smiley_35, "[折磨]", "[35]"), + KJEMOJI36(0, 1, R.mipmap.smiley_36, "[衰]", "[36]"), + KJEMOJI37(0, 1, R.mipmap.smiley_37, "[骷髅]", "[37]"), + KJEMOJI38(0, 1, R.mipmap.smiley_38, "[敲打]", "[38]"), + KJEMOJI39(0, 1, R.mipmap.smiley_39, "[再见]", "[39]"), + KJEMOJI40(0, 1, R.mipmap.smiley_40, "[擦汗]", "[40]"), + KJEMOJI41(0, 1, R.mipmap.smiley_41, "[抠鼻]", "[41]"), + KJEMOJI42(0, 1, R.mipmap.smiley_42, "[鼓掌]", "[42]"), + KJEMOJI43(0, 1, R.mipmap.smiley_43, "[糗大了]", "[43]"), + KJEMOJI44(0, 1, R.mipmap.smiley_44, "[坏笑]", "[44]"), + KJEMOJI45(0, 1, R.mipmap.smiley_45, "[左哼哼]", "[45]"), + KJEMOJI46(0, 1, R.mipmap.smiley_46, "[右哼哼]", "[46]"), + KJEMOJI47(0, 1, R.mipmap.smiley_47, "[哈欠]", "[47]"), + KJEMOJI48(0, 1, R.mipmap.smiley_48, "[鄙视]", "[48]"), + KJEMOJI49(0, 1, R.mipmap.smiley_49, "[委屈]", "[49]"), + KJEMOJI50(0, 1, R.mipmap.smiley_50, "[快哭了]", "[50]"), + KJEMOJI51(0, 1, R.mipmap.smiley_51, "[阴险]", "[51]"), + KJEMOJI52(0, 1, R.mipmap.smiley_52, "[亲亲]", "[52]"), + KJEMOJI53(0, 1, R.mipmap.smiley_53, "[吓]", "[53]"), + KJEMOJI54(0, 1, R.mipmap.smiley_54, "[可怜]", "[54]"), + KJEMOJI55(0, 1, R.mipmap.smiley_55, "[菜刀]", "[55]"), + KJEMOJI56(0, 1, R.mipmap.smiley_56, "[西瓜]", "[56]"), + KJEMOJI57(0, 1, R.mipmap.smiley_57, "[啤酒]", "[57]"), + KJEMOJI58(0, 1, R.mipmap.smiley_58, "[篮球]", "[58]"), + KJEMOJI59(0, 1, R.mipmap.smiley_59, "[乒乓]", "[59]"), + KJEMOJI60(0, 1, R.mipmap.smiley_60, "[咖啡]", "[60]"), + KJEMOJI61(0, 1, R.mipmap.smiley_61, "[饭]", "[61]"), + KJEMOJI62(0, 1, R.mipmap.smiley_62, "[猪头]", "[62]"), + KJEMOJI63(0, 1, R.mipmap.smiley_63, "[玫瑰]", "[63]"), + KJEMOJI64(0, 1, R.mipmap.smiley_64, "[凋谢]", "[64]"), + KJEMOJI65(0, 1, R.mipmap.smiley_65, "[嘴唇]", "[65]"), + KJEMOJI66(0, 1, R.mipmap.smiley_66, "[爱心]", "[66]"), + KJEMOJI67(0, 1, R.mipmap.smiley_67, "[心碎]", "[67]"), + KJEMOJI68(0, 1, R.mipmap.smiley_68, "[蛋糕]", "[68]"), + KJEMOJI69(0, 1, R.mipmap.smiley_69, "[闪电]", "[69]"), + KJEMOJI70(0, 1, R.mipmap.smiley_70, "[炸弹]", "[70]"), + KJEMOJI71(0, 1, R.mipmap.smiley_71, "[刀]", "[71]"), + KJEMOJI72(0, 1, R.mipmap.smiley_72, "[足球]", "[72]"), + KJEMOJI73(0, 1, R.mipmap.smiley_73, "[瓢虫]", "[73]"), + KJEMOJI74(0, 1, R.mipmap.smiley_74, "[便便]", "[74]"), + KJEMOJI75(0, 1, R.mipmap.smiley_75, "[月亮]", "[75]"), + KJEMOJI76(0, 1, R.mipmap.smiley_76, "[太阳]", "[76]"), + KJEMOJI77(0, 1, R.mipmap.smiley_77, "[礼物]", "[77]"), + KJEMOJI78(0, 1, R.mipmap.smiley_78, "[拥抱]", "[78]"), + KJEMOJI79(0, 1, R.mipmap.smiley_79, "[强]", "[79]"), + KJEMOJI80(0, 1, R.mipmap.smiley_80, "[弱]", "[80]"), + KJEMOJI81(0, 1, R.mipmap.smiley_81, "[握手]", "[81]"), + KJEMOJI82(0, 1, R.mipmap.smiley_82, "[胜利]", "[82]"), + KJEMOJI83(0, 1, R.mipmap.smiley_83, "[抱拳]", "[83]"), + KJEMOJI84(0, 1, R.mipmap.smiley_84, "[勾引]", "[84]"), + KJEMOJI85(0, 1, R.mipmap.smiley_85, "[拳头]", "[85]"), + KJEMOJI86(0, 1, R.mipmap.smiley_86, "[差劲]", "[86]"), + KJEMOJI87(0, 1, R.mipmap.smiley_87, "[爱你]", "[87]"), + KJEMOJI88(0, 1, R.mipmap.smiley_88, "[NO]", "[88]"), + KJEMOJI89(0, 1, R.mipmap.smiley_89, "[OK]", "[89]"), + KJEMOJI90(0, 1, R.mipmap.smiley_90, "[爱情]", "[90]"), + KJEMOJI91(0, 1, R.mipmap.smiley_91, "[飞吻]", "[91]"), + KJEMOJI92(0, 1, R.mipmap.smiley_92, "[跳跳]", "[92]"), + KJEMOJI93(0, 1, R.mipmap.smiley_93, "[发抖]", "[93]"), + KJEMOJI94(0, 1, R.mipmap.smiley_94, "[怄火]", "[94]"), + KJEMOJI95(0, 1, R.mipmap.smiley_95, "[转圈]", "[95]"), + KJEMOJI96(0, 1, R.mipmap.smiley_96, "[磕头]", "[96]"), + KJEMOJI97(0, 1, R.mipmap.smiley_97, "[回头]", "[97]"), + KJEMOJI98(0, 1, R.mipmap.smiley_98, "[跳绳]", "[98]"), + KJEMOJI99(0, 1, R.mipmap.smiley_99, "[投降]", "[99]"), + KJEMOJI100(0, 1, R.mipmap.smiley_100, "[激动]", "[100]"), + KJEMOJI101(0, 1, R.mipmap.smiley_101, "[乱舞]", "[101]"), + KJEMOJI102(0, 1, R.mipmap.smiley_102, "[献吻]", "[102]"), + KJEMOJI103(0, 1, R.mipmap.smiley_103, "[左太极]", "[103]"), + KJEMOJI104(0, 1, R.mipmap.smiley_104, "[右太极]", "[104]"), + + GITHUB0(1, 1, R.mipmap.bowtie, ":bowtie:", ":bowtie:"), + GITHUB1(1, 1, R.mipmap.smile, ":smile:", ":smile:"), + GITHUB2(1, 1, R.mipmap.laughing, ":laughing:", ":laughing:"), + GITHUB3(1, 1, R.mipmap.blush, ":blush:", ":blush:"), + GITHUB4(1, 1, R.mipmap.smiley, ":smiley:", ":smiley:"), + GITHUB5(1, 1, R.mipmap.relaxed, ":relaxed:", ":relaxed:"), + GITHUB6(1, 1, R.mipmap.smirk, ":smirk:", ":smirk:"), + GITHUB7(1, 1, R.mipmap.heart_eyes, ":heart_eyes:", ":heart_eyes:"), + GITHUB8(1, 1, R.mipmap.kissing_heart, ":kissing_heart:", ":kissing_heart:"), + GITHUB9(1, 1, R.mipmap.kissing_closed_eyes, ":kissing_closed_eyes:", ":kissing_closed_eyes:"), + GITHUB10(1, 1, R.mipmap.flushed, ":flushed:", ":flushed:"), + GITHUB11(1, 1, R.mipmap.relieved, ":relieved:", ":relieved:"), + GITHUB12(1, 1, R.mipmap.satisfied, ":satisfied:", ":satisfied:"), + GITHUB13(1, 1, R.mipmap.grin, ":grin:", ":grin:"), + GITHUB14(1, 1, R.mipmap.wink, ":wink:", ":wink:"), + GITHUB15(1, 1, R.mipmap.stuck_out_tongue_winking_eye, ":stuck_out_tongue_winking_eye:", ":stuck_out_tongue_winking_eye:"), + GITHUB16(1, 1, R.mipmap.stuck_out_tongue_closed_eyes, ":stuck_out_tongue_closed_eyes:", ":stuck_out_tongue_closed_eyes:"), + GITHUB17(1, 1, R.mipmap.grinning, ":grinning:", ":grinning:"), + GITHUB18(1, 1, R.mipmap.kissing, ":kissing:", ":kissing:"), + GITHUB19(1, 1, R.mipmap.kissing_smiling_eyes, ":kissing_smiling_eyes:", ":kissing_smiling_eyes:"), + GITHUB20(1, 1, R.mipmap.stuck_out_tongue, ":stuck_out_tongue:", ":stuck_out_tongue:"), + GITHUB21(1, 1, R.mipmap.sleeping, ":sleeping:", ":sleeping:"), + GITHUB22(1, 1, R.mipmap.worried, ":worried:", ":worried:"), + GITHUB23(1, 1, R.mipmap.frowning, ":frowning:", ":frowning:"), + GITHUB24(1, 1, R.mipmap.anguished, ":anguished:", ":anguished:"), + GITHUB25(1, 1, R.mipmap.open_mouth, ":open_mouth:", ":open_mouth:"), + GITHUB26(1, 1, R.mipmap.grimacing, ":grimacing:", ":grimacing:"), + GITHUB27(1, 1, R.mipmap.confused, ":confused:", ":confused:"), + GITHUB28(1, 1, R.mipmap.hushed, ":hushed:", ":hushed:"), + GITHUB29(1, 1, R.mipmap.expressionless, ":expressionless:", ":expressionless:"), + GITHUB30(1, 1, R.mipmap.unamused, ":unamused:", ":unamused:"), + GITHUB31(1, 1, R.mipmap.sweat_smile, ":sweat_smile:", ":sweat_smile:"), + GITHUB32(1, 1, R.mipmap.sweat, ":sweat:", ":sweat:"), + GITHUB33(1, 1, R.mipmap.disappointed_relieved, ":disappointed_relieved:", ":disappointed_relieved:"), + GITHUB34(1, 1, R.mipmap.weary, ":weary:", ":weary:"), + GITHUB35(1, 1, R.mipmap.pensive, ":pensive:", ":pensive:"), + GITHUB36(1, 1, R.mipmap.disappointed, ":disappointed:", ":disappointed:"), + GITHUB37(1, 1, R.mipmap.confounded, ":confounded:", ":confounded:"), + GITHUB38(1, 1, R.mipmap.fearful, ":fearful:", ":fearful:"), + GITHUB39(1, 1, R.mipmap.cold_sweat, ":cold_sweat:", ":cold_sweat:"), + GITHUB40(1, 1, R.mipmap.persevere, ":persevere:", ":persevere:"), + GITHUB41(1, 1, R.mipmap.cry, ":cry:", ":cry:"), + GITHUB42(1, 1, R.mipmap.sob, ":sob:", ":sob:"), + GITHUB43(1, 1, R.mipmap.joy, ":joy:", ":joy:"), + GITHUB44(1, 1, R.mipmap.astonished, ":astonished:", ":astonished:"), + GITHUB45(1, 1, R.mipmap.scream, ":scream:", ":scream:"), + GITHUB46(1, 1, R.mipmap.neckbeard, ":neckbeard:", ":neckbeard:"), + GITHUB47(1, 1, R.mipmap.tired_face, ":tired_face:", ":tired_face:"), + GITHUB48(1, 1, R.mipmap.angry, ":angry:", ":angry:"), + GITHUB49(1, 1, R.mipmap.rage, ":rage:", ":rage:"), + GITHUB50(1, 1, R.mipmap.triumph, ":triumph:", ":triumph:"), + GITHUB51(1, 1, R.mipmap.sleepy, ":sleepy:", ":sleepy:"), + GITHUB52(1, 1, R.mipmap.yum, ":yum:", ":yum:"), + GITHUB53(1, 1, R.mipmap.mask, ":mask:", ":mask:"), + GITHUB54(1, 1, R.mipmap.sunglasses, ":sunglasses:", ":sunglasses:"), + GITHUB55(1, 1, R.mipmap.dizzy_face, ":dizzy_face:", ":dizzy_face:"), + GITHUB56(1, 1, R.mipmap.imp, ":imp:", ":imp:"), + GITHUB57(1, 1, R.mipmap.smiling_imp, ":smiling_imp:", ":smiling_imp:"), + GITHUB58(1, 1, R.mipmap.neutral_face, ":neutral_face:", ":neutral_face:"), + GITHUB59(1, 1, R.mipmap.no_mouth, ":no_mouth:", ":no_mouth:"), + GITHUB60(1, 1, R.mipmap.innocent, ":innocent:", ":innocent:"), + GITHUB61(1, 1, R.mipmap.alien, ":alien:", ":alien:"), + GITHUB62(1, 1, R.mipmap.yellow_heart, ":yellow_heart:", ":yellow_heart:"), + GITHUB63(1, 1, R.mipmap.blue_heart, ":blue_heart:", ":blue_heart:"), + GITHUB64(1, 1, R.mipmap.purple_heart, ":purple_heart:", ":purple_hert:"), + GITHUB65(1, 1, R.mipmap.heart, ":heart:", ":heart:"), + GITHUB66(1, 1, R.mipmap.green_heart, ":green_heart:", ":green_heart:"), + GITHUB67(1, 1, R.mipmap.broken_heart, ":broken_heart:", ":broken_heart:"), + GITHUB68(1, 1, R.mipmap.heartbeat, ":heartbeat:", ":heartbeat:"), + GITHUB69(1, 1, R.mipmap.heartpulse, ":heartpulse:", ":heartpulse:"), + GITHUB70(1, 1, R.mipmap.two_hearts, ":two_hearts:", ":two_hearts:"), + GITHUB71(1, 1, R.mipmap.revolving_hearts, ":revolving_hearts:", ":revolving_hearts:"), + GITHUB72(1, 1, R.mipmap.cupid, ":cupid:", ":cupid:"), + GITHUB73(1, 1, R.mipmap.sparkling_heart, ":sparkling_heart:", ":sparkling_heart:"), + GITHUB74(1, 1, R.mipmap.sparkles, ":sparkles:", ":sparkles:"), + GITHUB75(1, 1, R.mipmap.star, ":star:", ":star:"), + GITHUB76(1, 1, R.mipmap.star2, ":star2:", ":star2:"), + GITHUB77(1, 1, R.mipmap.dizzy, ":dizzy:", ":dizzy:"), + GITHUB78(1, 1, R.mipmap.boom, ":boom:", ":boom:"), + GITHUB79(1, 1, R.mipmap.collision, ":collision:", ":collision:"), + GITHUB80(1, 1, R.mipmap.anger, ":anger:", ":anger:"), + GITHUB81(1, 1, R.mipmap.exclamation, ":exclamation:", ":exclamation:"), + GITHUB82(1, 1, R.mipmap.question, ":question:", ":question:"), + GITHUB83(1, 1, R.mipmap.grey_exclamation, ":grey_exclamation:", ":grey_exclamation:"), + GITHUB84(1, 1, R.mipmap.grey_question, ":grey_question:", ":grey_question:"), + GITHUB85(1, 1, R.mipmap.zzz, ":zzz:", ":zzz:"), + GITHUB86(1, 1, R.mipmap.dash, ":dash:", ":dash:"), + GITHUB87(1, 1, R.mipmap.sweat_drops, ":sweat_drops:", ":sweat_drops:"), + GITHUB88(1, 1, R.mipmap.notes, ":notes:", ":notes:"), + GITHUB89(1, 1, R.mipmap.musical_note, ":musical_note:", ":musical_note:"), + GITHUB90(1, 1, R.mipmap.fire, ":fire:", ":fire:"), + GITHUB91(1, 1, R.mipmap.hankey, ":hankey:", ":hankey:"), + GITHUB92(1, 1, R.mipmap.poop, ":poop:", ":poop:"), + GITHUB93(1, 1, R.mipmap.shit, ":shit:", ":shit:"), + GITHUB94(1, 1, R.mipmap.thumbsup, ":+1:", ":+1:"), + GITHUB95(1, 1, R.mipmap.thumbsup, ":thumbsup:", ":thumbsup:"), + GITHUB96(1, 1, R.mipmap.the_1, ":-1:", ":-1:"), + GITHUB97(1, 1, R.mipmap.thumbsdown, ":thumbsdown:", ":thumbsdown:"), + GITHUB98(1, 1, R.mipmap.ok_hand, ":ok_hand:", ":ok_hand:"), + GITHUB99(1, 1, R.mipmap.punch, ":punch:", ":punch:"), + GITHUB100(1, 1, R.mipmap.facepunch, ":facepunch:", ":facepunch:"), + GITHUB101(1, 1, R.mipmap.fist, ":fist:", ":fist:"), + GITHUB102(1, 1, R.mipmap.v, ":v:", ":v:"), + GITHUB103(1, 1, R.mipmap.wave, ":wave:", ":wave:"), + GITHUB104(1, 1, R.mipmap.hand, ":hand:", ":hand:"), + GITHUB105(1, 1, R.mipmap.raised_hand, ":raised_hand:", ":raised_hand:"), + GITHUB106(1, 1, R.mipmap.open_hands, ":open_hands:", ":open_hands:"), + GITHUB107(1, 1, R.mipmap.point_up, ":point_up:", ":point_up:"), + GITHUB108(1, 1, R.mipmap.point_down, ":point_down:", ":point_down:"), + GITHUB109(1, 1, R.mipmap.point_left, ":point_left:", ":point_left:"), + GITHUB110(1, 1, R.mipmap.point_right, ":point_right:", ":point_right:"), + GITHUB111(1, 1, R.mipmap.raised_hands, ":raised_hands:", ":raised_hands:"), + GITHUB112(1, 1, R.mipmap.pray, ":pray:", ":pray:"), + GITHUB113(1, 1, R.mipmap.point_up_2, ":point_up_2:", ":point_up_2:"), + GITHUB114(1, 1, R.mipmap.clap, ":clap:", ":clap:"), + GITHUB115(1, 1, R.mipmap.muscle, ":muscle:", ":muscle:"), + GITHUB116(1, 1, R.mipmap.metal, ":metal:", ":metal:"), + GITHUB117(1, 1, R.mipmap.fu, ":fu:", ":fu:"), + GITHUB118(1, 1, R.mipmap.walking, ":walking:", ":walking:"), + GITHUB119(1, 1, R.mipmap.runner, ":runner:", ":runner:"), + GITHUB120(1, 1, R.mipmap.running, ":running:", ":running:"), + GITHUB121(1, 1, R.mipmap.couple, ":couple:", ":couple:"), + GITHUB122(1, 1, R.mipmap.family, ":family:", ":family:"), + GITHUB123(1, 1, R.mipmap.two_men_holding_hands, ":two_men_holding_hands:", ":two_men_holding_hands:"), + GITHUB124(1, 1, R.mipmap.two_women_holding_hands, ":two_women_holding_hands:", ":two_women_holding_hands:"), + GITHUB125(1, 1, R.mipmap.dancer, ":dancer:", ":dancer:"), + GITHUB126(1, 1, R.mipmap.dancers, ":dancers:", ":dancers:"), + GITHUB127(1, 1, R.mipmap.ok_woman, ":ok_woman:", ":ok_woman:"), + GITHUB128(1, 1, R.mipmap.no_good, ":no_good:", ":no_good:"), + GITHUB129(1, 1, R.mipmap.information_desk_person, ":information_desk_person:", ":information_desk_person:"), + GITHUB130(1, 1, R.mipmap.raising_hand, ":raising_hand:", ":raising_hand:"), + GITHUB131(1, 1, R.mipmap.bride_with_veil, ":bride_with_veil:", ":bride_with_veil:"), + GITHUB132(1, 1, R.mipmap.person_with_pouting_face, ":person_with_pouting_face:", ":person_with_pouting_face:"), + GITHUB133(1, 1, R.mipmap.person_frowning, ":person_frowning:", ":person_frowning:"), + GITHUB134(1, 1, R.mipmap.bow, ":bow:", ":bow:"), + GITHUB135(1, 1, R.mipmap.couplekiss, ":couplekiss:", ":couplekiss:"), + GITHUB136(1, 1, R.mipmap.couple_with_heart, ":couple_with_heart:", ":couple_with_heart:"), + GITHUB137(1, 1, R.mipmap.massage, ":massage:", ":massage:"), + GITHUB138(1, 1, R.mipmap.haircut, ":haircut:", ":haircut:"), + GITHUB139(1, 1, R.mipmap.nail_care, ":nail_care:", ":nail_care:"), + GITHUB140(1, 1, R.mipmap.boy, ":boy:", ":boy:"), + GITHUB141(1, 1, R.mipmap.girl, ":girl:", ":girl:"), + GITHUB142(1, 1, R.mipmap.woman, ":woman:", ":woman:"), + GITHUB143(1, 1, R.mipmap.man, ":man:", ":man:"), + GITHUB144(1, 1, R.mipmap.baby, ":baby:", ":baby:"), + GITHUB145(1, 1, R.mipmap.older_woman, ":older_woman:", ":older_woman:"), + GITHUB146(1, 1, R.mipmap.older_man, ":older_man:", ":older_man:"), + GITHUB147(1, 1, R.mipmap.person_with_blond_hair, ":person_with_blond_hair:", ":person_with_blond_hair:"), + GITHUB148(1, 1, R.mipmap.man_with_gua_pi_mao, ":man_with_gua_pi_mao:", ":man_with_gua_pi_mao:"), + GITHUB149(1, 1, R.mipmap.man_with_turban, ":man_with_turban:", ":man_with_turban:"), + GITHUB150(1, 1, R.mipmap.construction_worker, ":construction_worker:", ":construction_worker:"), + GITHUB151(1, 1, R.mipmap.cop, ":cop:", ":cop:"), + GITHUB152(1, 1, R.mipmap.angel, ":angel:", ":angel:"), + GITHUB153(1, 1, R.mipmap.princess, ":princess:", ":princess:"), + GITHUB154(1, 1, R.mipmap.smiley_cat, ":smiley_cat:", ":smiley_cat:"), + GITHUB155(1, 1, R.mipmap.smile_cat, ":smile_cat:", ":smile_cat:"), + GITHUB156(1, 1, R.mipmap.heart_eyes_cat, ":heart_eyes_cat:", ":heart_eyes_cat:"), + GITHUB157(1, 1, R.mipmap.kissing_cat, ":kissing_cat:", ":kissing_cat:"), + GITHUB158(1, 1, R.mipmap.smirk_cat, ":smirk_cat:", ":smirk_cat:"), + GITHUB159(1, 1, R.mipmap.scream_cat, ":scream_cat:", ":scream_cat:"), + GITHUB160(1, 1, R.mipmap.crying_cat_face, ":crying_cat_face:", ":crying_cat_face:"), + GITHUB161(1, 1, R.mipmap.joy_cat, ":joy_cat:", ":joy_cat:"), + GITHUB162(1, 1, R.mipmap.pouting_cat, ":pouting_cat:", ":pouting_cat:"), + GITHUB163(1, 1, R.mipmap.japanese_ogre, ":japanese_ogre:", ":japanese_ogre:"), + GITHUB164(1, 1, R.mipmap.japanese_goblin, ":japanese_goblin:", ":japanese_goblin:"), + GITHUB165(1, 1, R.mipmap.see_no_evil, ":see_no_evil:", ":see_no_evil:"), + GITHUB166(1, 1, R.mipmap.hear_no_evil, ":hear_no_evil:", ":hear_no_evil:"), + GITHUB167(1, 1, R.mipmap.speak_no_evil, ":speak_no_evil:", ":speak_no_evil:"), + GITHUB168(1, 1, R.mipmap.guardsman, ":guardsman:", ":guardsman:"), + GITHUB169(1, 1, R.mipmap.skull, ":skull:", ":skull:"), + GITHUB170(1, 1, R.mipmap.feet, ":feet:", ":feet:"), + GITHUB171(1, 1, R.mipmap.lips, ":lips:", ":lips:"), + GITHUB172(1, 1, R.mipmap.kiss, ":kiss:", ":kiss:"), + GITHUB173(1, 1, R.mipmap.droplet, ":droplet:", ":droplet:"), + GITHUB174(1, 1, R.mipmap.ear, ":ear:", ":ear:"), + GITHUB175(1, 1, R.mipmap.eyes, ":eyes:", ":eyes:"), + GITHUB176(1, 1, R.mipmap.nose, ":nose:", ":nose:"), + GITHUB177(1, 1, R.mipmap.tongue, ":tongue:", ":tongue:"), + GITHUB178(1, 1, R.mipmap.love_letter, ":love_letter:", ":love_letter:"), + GITHUB179(1, 1, R.mipmap.bust_in_silhouette, ":bust_in_silhouette:", ":bust_in_silhouette:"), + GITHUB180(1, 1, R.mipmap.busts_in_silhouette, ":busts_in_silhouette:", ":busts_in_silhouette:"), + GITHUB181(1, 1, R.mipmap.speech_balloon, ":speech_balloon:", ":speech_balloon:"), + GITHUB182(1, 1, R.mipmap.thought_balloon, ":thought_balloon:", ":thought_balloon:"), + GITHUB183(1, 1, R.mipmap.feelsgood, ":feelsgood:", ":feelsgood:"), + GITHUB184(1, 1, R.mipmap.finnadie, ":finnadie:", ":finnadie:"), + GITHUB185(1, 1, R.mipmap.goberserk, ":goberserk:", ":goberserk:"), + GITHUB186(1, 1, R.mipmap.godmode, ":godmode:", ":godmode:"), + GITHUB187(1, 1, R.mipmap.hurtrealbad, ":hurtrealbad:", ":hurtrealbad:"), + GITHUB188(1, 1, R.mipmap.rage1, ":rage1:", ":rage1:"), + GITHUB189(1, 1, R.mipmap.rage2, ":rage2:", ":rage2:"), + GITHUB190(1, 1, R.mipmap.rage3, ":rage3:", ":rage3:"), + GITHUB191(1, 1, R.mipmap.rage4, ":rage4:", ":rage4:"), + GITHUB192(1, 1, R.mipmap.suspect, ":suspect:", ":suspect:"), + GITHUB193(1, 1, R.mipmap.trollface, ":trollface:", ":trollface:"), + + Nature0(2, 1, R.mipmap.sunny, ":sunny:", ":sunny:"), + Nature1(2, 1, R.mipmap.umbrella, ":umbrella:", ":umbrella:"), + Nature2(2, 1, R.mipmap.cloud, ":cloud:", ":cloud:"), + Nature3(2, 1, R.mipmap.snowflake, ":snowflake:", ":snowflake:"), + Nature4(2, 1, R.mipmap.snowman, ":snowman:", ":snowman:"), + Nature5(2, 1, R.mipmap.zap, ":zap:", ":zap:"), + Nature6(2, 1, R.mipmap.cyclone, ":cyclone:", ":cyclone:"), + Nature7(2, 1, R.mipmap.foggy, ":foggy:", ":foggy:"), + Nature8(2, 1, R.mipmap.ocean, ":ocean:", ":ocean:"), + Nature9(2, 1, R.mipmap.cat, ":cat:", ":cat:"), + Nature10(2, 1, R.mipmap.dog, ":dog:", ":dog:"), + Nature11(2, 1, R.mipmap.mouse, ":mouse:", ":mouse:"), + Nature12(2, 1, R.mipmap.hamster, ":hamster:", ":hamster:"), + Nature13(2, 1, R.mipmap.rabbit, ":rabbit:", ":rabbit:"), + Nature14(2, 1, R.mipmap.wolf, ":wolf:", ":wolf:"), + Nature15(2, 1, R.mipmap.frog, ":frog:", ":frog:"), + Nature16(2, 1, R.mipmap.tiger, ":tiger:", ":tiger:"), + Nature17(2, 1, R.mipmap.koala, ":koala:", ":koala:"), + Nature18(2, 1, R.mipmap.bear, ":bear:", ":bear:"), + Nature19(2, 1, R.mipmap.pig, ":pig:", ":pig:"), + Nature20(2, 1, R.mipmap.pig_nose, ":pig_nose:", ":pig_nose:"), + Nature21(2, 1, R.mipmap.cow, ":cow:", ":cow:"), + Nature22(2, 1, R.mipmap.boar, ":boar:", ":boar:"), + Nature23(2, 1, R.mipmap.monkey_face, ":monkey_face:", ":monkey_face:"), + Nature24(2, 1, R.mipmap.monkey, ":monkey:", ":monkey:"), + Nature25(2, 1, R.mipmap.horse, ":horse:", ":horse:"), + Nature26(2, 1, R.mipmap.racehorse, ":racehorse:", ":racehorse:"), + Nature27(2, 1, R.mipmap.camel, ":camel:", ":camel:"), + Nature28(2, 1, R.mipmap.sheep, ":sheep:", ":sheep:"), + Nature29(2, 1, R.mipmap.elephant, ":elephant:", ":elephant:"), + Nature30(2, 1, R.mipmap.panda_face, ":panda_face:", ":panda_face:"), + Nature31(2, 1, R.mipmap.snake, ":snake:", ":snake:"), + Nature32(2, 1, R.mipmap.bird, ":bird:", ":bird:"), + Nature33(2, 1, R.mipmap.baby_chick, ":baby_chick:", ":baby_chick:"), + Nature34(2, 1, R.mipmap.hatched_chick, ":hatched_chick:", ":hatched_chick:"), + Nature35(2, 1, R.mipmap.hatching_chick, ":hatching_chick:", ":hatching_chick:"), + Nature36(2, 1, R.mipmap.chicken, ":chicken:", ":chicken:"), + Nature37(2, 1, R.mipmap.penguin, ":penguin:", ":penguin:"), + Nature38(2, 1, R.mipmap.turtle, ":turtle:", ":turtle:"), + Nature39(2, 1, R.mipmap.bug, ":bug:", ":bug:"), + Nature40(2, 1, R.mipmap.honeybee, ":honeybee:", ":honeybee:"), + Nature41(2, 1, R.mipmap.ant, ":ant:", ":ant:"), + Nature42(2, 1, R.mipmap.beetle, ":beetle:", ":beetle:"), + Nature43(2, 1, R.mipmap.snail, ":snail:", ":snail:"), + Nature44(2, 1, R.mipmap.octopus, ":octopus:", ":octopus:"), + Nature45(2, 1, R.mipmap.tropical_fish, ":tropical_fish:", ":tropical_fish:"), + Nature46(2, 1, R.mipmap.fish, ":fish:", ":fish:"), + Nature47(2, 1, R.mipmap.whale, ":whale:", ":whale:"), + Nature48(2, 1, R.mipmap.whale2, ":whale2:", ":whale2:"), + Nature49(2, 1, R.mipmap.dolphin, ":dolphin:", ":dolphin:"), + Nature50(2, 1, R.mipmap.cow2, ":cow2:", ":cow2:"), + Nature51(2, 1, R.mipmap.ram, ":ram:", ":ram:"), + Nature52(2, 1, R.mipmap.rat, ":rat:", ":rat:"), + Nature53(2, 1, R.mipmap.water_buffalo, ":water_buffalo:", ":water_buffalo:"), + Nature54(2, 1, R.mipmap.tiger2, ":tiger2:", ":tiger2:"), + Nature55(2, 1, R.mipmap.rabbit2, ":rabbit2:", ":rabbit2:"), + Nature56(2, 1, R.mipmap.dragon, ":dragon:", ":dragon:"), + Nature57(2, 1, R.mipmap.goat, ":goat:", ":goat:"), + Nature58(2, 1, R.mipmap.rooster, ":rooster:", ":rooster:"), + Nature59(2, 1, R.mipmap.dog2, ":dog2:", ":dog2:"), + Nature60(2, 1, R.mipmap.pig2, ":pig2:", ":pig2:"), + Nature61(2, 1, R.mipmap.mouse2, ":mouse2:", ":mouse2:"), + Nature62(2, 1, R.mipmap.ox, ":ox:", ":ox:"), + Nature63(2, 1, R.mipmap.dragon_face, ":dragon_face:", ":dragon_face:"), + Nature64(2, 1, R.mipmap.blowfish, ":blowfish:", ":blowfish:"), + Nature65(2, 1, R.mipmap.crocodile, ":crocodile:", ":crocodile:"), + Nature66(2, 1, R.mipmap.dromedary_camel, ":dromedary_camel:", ":dromedary_camel:"), + Nature67(2, 1, R.mipmap.leopard, ":leopard:", ":leopard:"), + Nature68(2, 1, R.mipmap.cat2, ":cat2:", ":cat2:"), + Nature69(2, 1, R.mipmap.poodle, ":poodle:", ":poodle:"), + Nature70(2, 1, R.mipmap.paw_prints, ":paw_prints:", ":paw_prints:"), + Nature71(2, 1, R.mipmap.bouquet, ":bouquet:", ":bouquet:"), + Nature72(2, 1, R.mipmap.cherry_blossom, ":cherry_blossom:", ":cherry_blossom:"), + Nature73(2, 1, R.mipmap.tulip, ":tulip:", ":tulip:"), + Nature74(2, 1, R.mipmap.four_leaf_clover, ":four_leaf_clover:", ":four_leaf_clover:"), + Nature75(2, 1, R.mipmap.rose, ":rose:", ":rose:"), + Nature76(2, 1, R.mipmap.sunflower, ":sunflower:", ":sunflower:"), + Nature77(2, 1, R.mipmap.hibiscus, ":hibiscus:", ":hibiscus:"), + Nature78(2, 1, R.mipmap.maple_leaf, ":maple_leaf:", ":maple_leaf:"), + Nature79(2, 1, R.mipmap.leaves, ":leaves:", ":leaves:"), + Nature80(2, 1, R.mipmap.fallen_leaf, ":fallen_leaf:", ":fallen_leaf:"), + Nature81(2, 1, R.mipmap.herb, ":herb:", ":herb:"), + Nature82(2, 1, R.mipmap.mushroom, ":mushroom:", ":mushroom:"), + Nature83(2, 1, R.mipmap.cactus, ":cactus:", ":cactus:"), + Nature84(2, 1, R.mipmap.palm_tree, ":palm_tree:", ":palm_tree:"), + Nature85(2, 1, R.mipmap.evergreen_tree, ":evergreen_tree:", ":evergreen_tree:"), + Nature86(2, 1, R.mipmap.deciduous_tree, ":deciduous_tree:", ":deciduous_tree:"), + Nature87(2, 1, R.mipmap.chestnut, ":chestnut:", ":chestnut:"), + Nature88(2, 1, R.mipmap.seedling, ":seedling:", ":seedling:"), + Nature89(2, 1, R.mipmap.blossom, ":blossom:", ":blossom:"), + Nature90(2, 1, R.mipmap.ear_of_rice, ":ear_of_rice:", ":ear_of_rice:"), + Nature91(2, 1, R.mipmap.shell, ":shell:", ":shell:"), + Nature92(2, 1, R.mipmap.globe_with_meridians, ":globe_with_meridians:", ":globe_with_meridians:"), + Nature93(2, 1, R.mipmap.sun_with_face, ":sun_with_face:", ":sun_with_face:"), + Nature94(2, 1, R.mipmap.full_moon_with_face, ":full_moon_with_face:", ":full_moon_with_face:"), + Nature95(2, 1, R.mipmap.new_moon_with_face, ":new_moon_with_face:", ":new_moon_with_face:"), + Nature96(2, 1, R.mipmap.new_moon, ":new_moon:", ":new_moon:"), + Nature97(2, 1, R.mipmap.waxing_crescent_moon, ":waxing_crescent_moon:", ":waxing_crescent_moon:"), + Nature98(2, 1, R.mipmap.first_quarter_moon, ":first_quarter_moon:", ":first_quarter_moon:"), + Nature99(2, 1, R.mipmap.waxing_gibbous_moon, ":waxing_gibbous_moon:", ":waxing_gibbous_moon:"), + Nature100(2, 1, R.mipmap.full_moon, ":full_moon:", ":full_moon:"), + Nature101(2, 1, R.mipmap.waning_gibbous_moon, ":waning_gibbous_moon:", ":waning_gibbous_moon:"), + Nature102(2, 1, R.mipmap.last_quarter_moon, ":last_quarter_moon:", ":last_quarter_moon:"), + Nature103(2, 1, R.mipmap.waning_crescent_moon, ":waning_crescent_moon:", ":waning_crescent_moon:"), + Nature104(2, 1, R.mipmap.last_quarter_moon_with_face, ":last_quarter_moon_with_face:", ":last_quarter_moon_with_face:"), + Nature105(2, 1, R.mipmap.first_quarter_moon_with_face, ":first_quarter_moon_with_face:", ":first_quarter_moon_with_face:"), + Nature106(2, 1, R.mipmap.moon, ":moon:", ":moon:"), + Nature107(2, 1, R.mipmap.earth_africa, ":earth_africa:", ":earth_africa:"), + Nature108(2, 1, R.mipmap.earth_americas, ":earth_americas:", ":earth_americas:"), + Nature109(2, 1, R.mipmap.earth_asia, ":earth_asia:", ":earth_asia:"), + Nature110(2, 1, R.mipmap.volcano, ":volcano:", ":volcano:"), + Nature111(2, 1, R.mipmap.milky_way, ":milky_way:", ":milky_way:"), + Nature112(2, 1, R.mipmap.partly_sunny, ":partly_sunny:", ":partly_sunny:"), + Nature113(2, 1, R.mipmap.octocat, ":octocat:", ":octocat:"), + Nature114(2, 1, R.mipmap.squirrel, ":squirrel:", ":squirrel:"); + + /********************************* + * 操作 + **************************************/ private String emojiStr; private String remote; private int value; @@ -817,7 +458,7 @@ public enum DisplayRules { private static Map sEmojiMap; private DisplayRules(int type, int value, int resId, String cls, - String remote) { + String remote) { this.type = type; this.emojiStr = cls; this.value = value; diff --git a/app/src/main/java/net/oschina/app/emoji/EmojiKeyboardFragment.java b/app/src/main/java/net/oschina/app/emoji/EmojiKeyboardFragment.java index 00154dc16ceaf3f6d75cf23d1fd72501dc6314ba..a36f9267bab42f5ac207d918d339ce37073e6881 100644 --- a/app/src/main/java/net/oschina/app/emoji/EmojiKeyboardFragment.java +++ b/app/src/main/java/net/oschina/app/emoji/EmojiKeyboardFragment.java @@ -1,7 +1,5 @@ package net.oschina.app.emoji; -import net.oschina.app.R; -import net.oschina.app.emoji.SoftKeyboardStateHelper.SoftKeyboardStateListener; import android.content.Context; import android.os.Bundle; import android.support.annotation.Nullable; @@ -16,6 +14,9 @@ import android.widget.EditText; import android.widget.LinearLayout; import android.widget.RadioGroup; +import net.oschina.app.R; +import net.oschina.app.emoji.SoftKeyboardStateHelper.SoftKeyboardStateListener; + public class EmojiKeyboardFragment extends Fragment implements SoftKeyboardStateListener { @@ -30,22 +31,30 @@ public class EmojiKeyboardFragment extends Fragment implements private OnEmojiClickListener listener; public static int EMOJI_TAB_CONTENT; + private boolean isDelegate; + private SoftKeyboardStateHelper mKeyboardHelper; @Override public View onCreateView(LayoutInflater inflater, - @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - super.onCreateView(inflater, container, savedInstanceState); - mRootView = (LinearLayout) inflater.inflate(R.layout.frag_keyboard, - container, false); - initWidget(mRootView); + @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + + if (null != mRootView) { + ViewGroup parent = (ViewGroup) mRootView.getParent(); + if (null != parent) { + parent.removeView(mRootView); + } + } else { + mRootView = (LinearLayout) inflater.inflate(R.layout.frag_keyboard, container, false); + initWidget(mRootView); + } return mRootView; } private void initWidget(View rootView) { // bottom mEmojiBottom = (RadioGroup) rootView.findViewById(R.id.emoji_bottom); - mEmojiBottom.setVisibility(View.VISIBLE); + //mEmojiBottom.setVisibility(View.VISIBLE); EMOJI_TAB_CONTENT = mEmojiBottom.getChildCount() - 1; // 减一是因为有一个删除按钮 mEmojiTabs = new View[EMOJI_TAB_CONTENT]; if (EMOJI_TAB_CONTENT <= 1) { // 只有一个分类的时候就不显示了 @@ -66,23 +75,20 @@ public class EmojiKeyboardFragment extends Fragment implements }); // content必须放在bottom下面初始化 - mEmojiContent = (LinearLayout) rootView - .findViewById(R.id.emoji_content); + mEmojiContent = (LinearLayout) rootView.findViewById(R.id.emoji_content); mEmojiPager = (ViewPager) mEmojiContent.findViewById(R.id.emoji_pager); - adapter = new EmojiPagerAdapter(getFragmentManager(), - EMOJI_TAB_CONTENT, listener); + adapter = new EmojiPagerAdapter(getChildFragmentManager(), EMOJI_TAB_CONTENT, listener); mEmojiPager.setAdapter(adapter); - mEmojiContent.setVisibility(View.VISIBLE); + //mEmojiContent.setVisibility(View.VISIBLE); - mKeyboardHelper = new SoftKeyboardStateHelper(getActivity().getWindow() - .getDecorView()); + mKeyboardHelper = new SoftKeyboardStateHelper(getActivity().getWindow().getDecorView()); mKeyboardHelper.addSoftKeyboardStateListener(this); } /** * 底部栏点击事件监听器 - * - * @param indexfff + * + * @param index * @return */ private OnClickListener getBottomBarClickListener(final int index) { @@ -111,8 +117,10 @@ public class EmojiKeyboardFragment extends Fragment implements * 隐藏Emoji并显示软键盘 */ public void hideEmojiKeyBoard() { - mEmojiBottom.setVisibility(View.GONE); - mEmojiContent.setVisibility(View.GONE); + if (!isDelegate) { + mEmojiContent.setVisibility(View.GONE); + mEmojiBottom.setVisibility(View.GONE); + } } /** @@ -148,16 +156,23 @@ public class EmojiKeyboardFragment extends Fragment implements */ @Override public void onSoftKeyboardOpened(int keyboardHeightInPx) { - mEmojiBottom.setVisibility(View.GONE); - mEmojiContent.setVisibility(View.GONE); + if (!isDelegate) { + mEmojiContent.setVisibility(View.GONE); + mEmojiBottom.setVisibility(View.GONE); + } } @Override - public void onSoftKeyboardClosed() {} + public void onSoftKeyboardClosed() { + } @Override public void onStop() { super.onStop(); hideSoftKeyboard(); } + + public void setDelegate(boolean delegate) { + isDelegate = delegate; + } } diff --git a/app/src/main/java/net/oschina/app/emoji/InputHelper.java b/app/src/main/java/net/oschina/app/emoji/InputHelper.java index 786c6fe24115606292d56df763186b03aadc9881..04ed1b1e816e8a888af4078fdb03b869ee621d2f 100644 --- a/app/src/main/java/net/oschina/app/emoji/InputHelper.java +++ b/app/src/main/java/net/oschina/app/emoji/InputHelper.java @@ -19,16 +19,24 @@ import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.text.Spannable; import android.text.SpannableString; +import android.text.TextUtils; import android.text.style.ImageSpan; import android.view.KeyEvent; import android.widget.EditText; -import net.oschina.app.R; +import net.qiujuer.genius.ui.Ui; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** - * @author kymjs (http://www.kymjs.com) + * Emoji 表情解析类 */ public class InputHelper { + /** + * 删除Emoji表情 + * @param editText + */ public static void backspace(EditText editText) { if (editText == null) { return; @@ -55,60 +63,50 @@ public class InputHelper { * (I'm drunk, I go home) */ public static Spannable displayEmoji(Resources res, CharSequence s) { - String str = s.toString(); - Spannable spannable; - if (s instanceof Spannable) { - spannable = (Spannable) s; - } else { - // 构建文字span - spannable = new SpannableString(str); - } + return displayEmoji(res, s, (int) Ui.spToPx(res, 20)); + } + + public static Spannable displayEmoji(Resources res, CharSequence s, int size) { + return displayEmoji(res, new SpannableString(s), size); + } + + public static Spannable displayEmoji(Resources res, Spannable spannable) { + return displayEmoji(res, spannable, (int) Ui.spToPx(res, 20)); + } + + public static Spannable displayEmoji(Resources res, Spannable spannable, int size) { + String str = spannable.toString(); + if (!str.contains(":") && !str.contains("[")) { return spannable; } - for (int i = 0; i < str.length(); i++) { - int index1 = str.indexOf("[", i); - int length1 = str.indexOf("]", index1 + 1); - int index2 = str.indexOf(":", i); - int length2 = str.indexOf(":", index2 + 1); - int bound = (int) res.getDimension(R.dimen.space_20); + if (size == 0) + size = (int) Ui.spToPx(res, 20); - try { - if (index1 > 0) { - String emojiStr = str.substring(index1, length1 + "]".length()); - int resId = getEmojiResId(emojiStr); - if (resId > 0) { - // 构建图片span - Drawable drawable = res.getDrawable(resId); + Pattern pattern = Pattern.compile("(\\[[^\\[\\]:\\s\\n]+\\])|(:[^:\\[\\]\\s\\n]+:)"); + Matcher matcher = pattern.matcher(str); + while (matcher.find()) { + String emojiStr = matcher.group(); + if (TextUtils.isEmpty(emojiStr)) continue; + int resId = getEmojiResId(emojiStr); + if (resId <= 0) continue; + Drawable drawable = res.getDrawable(resId); + if (drawable == null) continue; + drawable.setBounds(0, 0, size, size); - drawable.setBounds(0, 20, bound, bound + 20); - ImageSpan span = new ImageSpan(drawable, - ImageSpan.ALIGN_BASELINE); - spannable.setSpan(span, index1, length1 + "]".length(), - Spannable.SPAN_INCLUSIVE_EXCLUSIVE); - } - } - if (index2 > 0) { - String emojiStr2 = str - .substring(index2, length2 + ":".length()); - int resId2 = getEmojiResId(emojiStr2); - if (resId2 > 0) { - Drawable emojiDrawable = res.getDrawable(resId2); - emojiDrawable.setBounds(0, 0, bound, bound); - // 构建图片span - ImageSpan imageSpan = new ImageSpan(emojiDrawable, str); - spannable.setSpan(imageSpan, index2, - length2 + ":".length(), - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - } - } - } catch (Exception e) { - } + ImageSpan span = new ImageSpan(drawable, ImageSpan.ALIGN_BOTTOM); + spannable.setSpan(span, matcher.start(), matcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } + return spannable; } + /** + * 输入Emoji表情到 EditText + * @param editText EditText + * @param emojicon Emojicon + */ public static void input2OSC(EditText editText, Emojicon emojicon) { if (editText == null || emojicon == null) { return; @@ -118,11 +116,11 @@ public class InputHelper { if (start < 0) { // 没有多选时,直接在当前光标处添加 editText.append(displayEmoji(editText.getResources(), - emojicon.getRemote())); + emojicon.getRemote(), (int) editText.getTextSize())); } else { // 将已选中的部分替换为表情(当长按文字时会多选刷中很多文字) Spannable str = displayEmoji(editText.getResources(), - emojicon.getRemote()); + emojicon.getRemote(), (int) editText.getTextSize()); editText.getText().replace(Math.min(start, end), Math.max(start, end), str, 0, str.length()); } diff --git a/app/src/main/java/net/oschina/app/emoji/KJEmojiConfig.java b/app/src/main/java/net/oschina/app/emoji/KJEmojiConfig.java index 76b2abb4297619539500c9bf393f860b629b959c..61669040b356e24c54637ffd73d366e587e820be 100644 --- a/app/src/main/java/net/oschina/app/emoji/KJEmojiConfig.java +++ b/app/src/main/java/net/oschina/app/emoji/KJEmojiConfig.java @@ -28,5 +28,5 @@ public class KJEmojiConfig { public static final int COUNT_IN_PAGE = 20; // 每页显示多少个表情(要减去一个删除符号:例如这里是三行七列) public static final int COLUMNS = 7; // 每页显示多少列 - public static final int DELETE_EMOJI_ID = R.drawable.btn_del; + public static final int DELETE_EMOJI_ID = R.mipmap.btn_del; } diff --git a/app/src/main/java/net/oschina/app/emoji/KJEmojiFragment.java b/app/src/main/java/net/oschina/app/emoji/KJEmojiFragment.java index edfd264145a6ab8021d81bd895dc867a258c58fd..2a75346946111a848ef83e25a7cef2c81d0c05a3 100644 --- a/app/src/main/java/net/oschina/app/emoji/KJEmojiFragment.java +++ b/app/src/main/java/net/oschina/app/emoji/KJEmojiFragment.java @@ -21,6 +21,7 @@ import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.view.ViewPager; import android.text.Editable; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; @@ -32,14 +33,15 @@ import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.RadioGroup; +import android.widget.Toast; import net.oschina.app.R; import net.oschina.app.emoji.SoftKeyboardStateHelper.SoftKeyboardStateListener; /** - * + * * @author kymjs (http://www.kymjs.com) - * + * */ public class KJEmojiFragment extends Fragment implements SoftKeyboardStateListener { @@ -65,10 +67,15 @@ public class KJEmojiFragment extends Fragment implements @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - super.onCreateView(inflater, container, savedInstanceState); - mRootView = (LinearLayout) inflater.inflate(R.layout.frag_main, - container, false); - initWidget(mRootView); + if (null != mRootView) { + ViewGroup parent = (ViewGroup) mRootView.getParent(); + if (null != parent) { + parent.removeView(mRootView); + } + }else { + mRootView = (LinearLayout) inflater.inflate(R.layout.frag_main, container,false); + initWidget(mRootView); + } return mRootView; } @@ -150,7 +157,7 @@ public class KJEmojiFragment extends Fragment implements /** * 底部栏点击事件监听器 - * + * * @param index * @return */ @@ -213,9 +220,9 @@ public class KJEmojiFragment extends Fragment implements */ public void showSoftKeyboard() { mEt.requestFocus(); - ((InputMethodManager) getActivity().getSystemService( - Context.INPUT_METHOD_SERVICE)).showSoftInput(mEt, - InputMethodManager.SHOW_FORCED); + ((InputMethodManager) getActivity() + .getSystemService(Context.INPUT_METHOD_SERVICE)) + .showSoftInput(mEt, InputMethodManager.SHOW_FORCED); } public View getEmojiTitle() { diff --git a/app/src/main/java/net/oschina/app/emoji/ScrollGridView.java b/app/src/main/java/net/oschina/app/emoji/ScrollGridView.java deleted file mode 100644 index 30686db45da6326f7b836abd20c4646e81b51ca4..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/emoji/ScrollGridView.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2015, 张涛. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package net.oschina.app.emoji; - -import android.content.Context; -import android.util.AttributeSet; -import android.widget.GridView; - -/** - * - * @author kymjs (http://www.kymjs.com) - */ -public class ScrollGridView extends GridView { - - public ScrollGridView(Context context) { - super(context); - } - - public ScrollGridView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public ScrollGridView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int height = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, - MeasureSpec.AT_MOST); - super.onMeasure(widthMeasureSpec, height); - } -} diff --git a/app/src/main/java/net/oschina/app/emoji/ToolbarFragment.java b/app/src/main/java/net/oschina/app/emoji/ToolbarFragment.java index cdf1b5d69f33d527bf954505710e5f1de6ba3be5..b63ff5f927c61efb65ddea04695328fae4df0564 100644 --- a/app/src/main/java/net/oschina/app/emoji/ToolbarFragment.java +++ b/app/src/main/java/net/oschina/app/emoji/ToolbarFragment.java @@ -13,7 +13,7 @@ import net.oschina.app.base.BaseFragment; public class ToolbarFragment extends BaseFragment { public interface OnActionClickListener { - public void onActionClick(ToolAction action); + void onActionClick(ToolAction action); } public enum ToolAction { @@ -37,9 +37,15 @@ public class ToolbarFragment extends BaseFragment { @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - mRootView = inflater.inflate(R.layout.fragment_detail_tool_bar, - container, false); - initView(mRootView); + if (null != mRootView) { + ViewGroup parent = (ViewGroup) mRootView.getParent(); + if (null != parent) { + parent.removeView(mRootView); + } + }else { + mRootView = inflater.inflate(R.layout.fragment_detail_tool_bar, container,false); + initView(mRootView); + } return mRootView; } diff --git a/app/src/main/java/net/oschina/app/fragment/AboutOSCFragment.java b/app/src/main/java/net/oschina/app/fragment/AboutOSCFragment.java index 892465ce3527b91a5a91630517e9b5dda5b8bef9..22129df7c4a8e51b8594b49b21703333238b3ba9 100644 --- a/app/src/main/java/net/oschina/app/fragment/AboutOSCFragment.java +++ b/app/src/main/java/net/oschina/app/fragment/AboutOSCFragment.java @@ -1,33 +1,32 @@ package net.oschina.app.fragment; -import net.oschina.app.R; -import net.oschina.app.base.BaseFragment; -import net.oschina.app.bean.SimpleBackPage; -import net.oschina.app.util.TDevice; -import net.oschina.app.util.UIHelper; -import net.oschina.app.util.UpdateManager; import android.os.Bundle; import android.support.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; + +import net.oschina.app.R; +import net.oschina.app.base.BaseFragment; +import net.oschina.app.util.TDevice; +import net.oschina.app.util.UIHelper; +import net.oschina.common.admin.Boss; + +import butterknife.Bind; import butterknife.ButterKnife; -import butterknife.InjectView; +import butterknife.OnClick; public class AboutOSCFragment extends BaseFragment { - @InjectView(R.id.tv_version) - TextView mTvVersionStatus; - - @InjectView(R.id.tv_version_name) + @Bind(R.id.tv_version_name) TextView mTvVersionName; @Override public View onCreateView(LayoutInflater inflater, - @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_about, container, false); - ButterKnife.inject(this, view); + ButterKnife.bind(this, view); initView(view); initData(); return view; @@ -35,64 +34,50 @@ public class AboutOSCFragment extends BaseFragment { @Override public void initView(View view) { - view.findViewById(R.id.rl_check_update).setOnClickListener(this); - view.findViewById(R.id.rl_feedback).setOnClickListener(this); - view.findViewById(R.id.rl_grade).setOnClickListener(this); - view.findViewById(R.id.rl_gitapp).setOnClickListener(this); + view.findViewById(R.id.tv_grade).setOnClickListener(this); + view.findViewById(R.id.tv_gitapp).setOnClickListener(this); view.findViewById(R.id.tv_oscsite).setOnClickListener(this); view.findViewById(R.id.tv_knowmore).setOnClickListener(this); } @Override public void initData() { - mTvVersionName.setText("V " + TDevice.getVersionName()); + mTvVersionName.setText(TDevice.getVersionName()); } @Override + @OnClick(R.id.img_portrait) public void onClick(View v) { final int id = v.getId(); switch (id) { - case R.id.rl_check_update: - onClickUpdate(); - break; - case R.id.rl_feedback: - showFeedBack(); - break; - case R.id.rl_grade: - TDevice.openAppInMarket(getActivity()); - break; - case R.id.rl_gitapp: - boolean res = TDevice.openAppActivity(getActivity(), - "net.oschina.gitapp", "net.oschina.gitapp.WelcomePage"); + case R.id.tv_grade: + TDevice.openAppInMarket(getActivity()); + break; + case R.id.tv_gitapp: + boolean res = TDevice.openAppActivity(getActivity(), + "net.oschina.gitapp", "net.oschina.gitapp.WelcomePage"); - if (!res) { - if (!TDevice.isHaveMarket(getActivity())) { - UIHelper.openSysBrowser(getActivity(), - "http://git.oschina.net/appclient"); - } else { - TDevice.gotoMarket(getActivity(), "net.oschina.gitapp"); + if (!res) { + if (!TDevice.isHaveMarket(getActivity())) { + UIHelper.openInternalBrowser(getActivity(), + "http://git.oschina.net/appclient"); + } else { + TDevice.gotoMarket(getActivity(), "net.oschina.gitapp"); + } } - } - break; - case R.id.tv_oscsite: - UIHelper.openBrowser(getActivity(), "https://www.oschina.net"); - break; - case R.id.tv_knowmore: - UIHelper.openBrowser(getActivity(), - "https://www.oschina.net/home/aboutosc"); - break; - default: - break; + break; + case R.id.tv_oscsite: + UIHelper.openInternalBrowser(getActivity(), "https://www.oschina.net"); + break; + case R.id.tv_knowmore: + UIHelper.openInternalBrowser(getActivity(), + "https://www.oschina.net/home/aboutosc"); + break; + case R.id.img_portrait: + Boss.verifyApp(getContext()); + break; + default: + break; } } - - private void onClickUpdate() { - new UpdateManager(getActivity(), true).checkUpdate(); - } - - private void showFeedBack() { - // TDevice.sendEmail(getActivity(), "用户反馈-OSC Android客户端", "", - // "apposchina@163.com"); - UIHelper.showSimpleBack(getActivity(), SimpleBackPage.FEED_BACK); - } } diff --git a/app/src/main/java/net/oschina/app/fragment/ActiveFragment.java b/app/src/main/java/net/oschina/app/fragment/ActiveFragment.java deleted file mode 100644 index 5657fc4b35c1d18561d1f196817e9f00fee4a247..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/fragment/ActiveFragment.java +++ /dev/null @@ -1,212 +0,0 @@ -package net.oschina.app.fragment; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Bundle; -import android.view.View; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemLongClickListener; - -import net.oschina.app.AppContext; -import net.oschina.app.R; -import net.oschina.app.adapter.ActiveAdapter; -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.base.BaseListFragment; -import net.oschina.app.bean.Active; -import net.oschina.app.bean.ActiveList; -import net.oschina.app.bean.Constants; -import net.oschina.app.bean.Notice; -import net.oschina.app.service.NoticeUtils; -import net.oschina.app.ui.MainActivity; -import net.oschina.app.ui.empty.EmptyLayout; -import net.oschina.app.util.DialogHelp; -import net.oschina.app.util.HTMLUtil; -import net.oschina.app.util.TDevice; -import net.oschina.app.util.UIHelper; -import net.oschina.app.util.XmlUtils; -import net.oschina.app.viewpagerfragment.NoticeViewPagerFragment; - -import java.io.InputStream; -import java.io.Serializable; - -/** - * 动态fragment - * - * @author FireAnt(http://my.oschina.net/LittleDY) - * @author kymjs (https://github.com/kymjs) - * @created 2014年10月22日 下午3:35:43 - * - */ -public class ActiveFragment extends BaseListFragment implements - OnItemLongClickListener { - - protected static final String TAG = ActiveFragment.class.getSimpleName(); - private static final String CACHE_KEY_PREFIX = "active_list"; - private boolean mIsWatingLogin; // 还没登陆 - - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (mErrorLayout != null) { - mIsWatingLogin = true; - mErrorLayout.setErrorType(EmptyLayout.NETWORK_ERROR); - mErrorLayout.setErrorMessage(getString(R.string.unlogin_tip)); - } - } - }; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - IntentFilter filter = new IntentFilter(Constants.INTENT_ACTION_LOGOUT); - getActivity().registerReceiver(mReceiver, filter); - } - - @Override - public void onDestroy() { - getActivity().unregisterReceiver(mReceiver); - super.onDestroy(); - } - - @Override - public void onResume() { - if (mIsWatingLogin) { - mCurrentPage = 0; - mState = STATE_REFRESH; - requestData(false); - } - refreshNotice(); - super.onResume(); - } - - /** - * 开始刷新请求 - */ - private void refreshNotice() { - Notice notice = MainActivity.mNotice; - if (notice == null) { - return; - } - if (notice.getAtmeCount() > 0 && mCatalog == ActiveList.CATALOG_ATME) { - onRefresh(); - } else if (notice.getReviewCount() > 0 - && mCatalog == ActiveList.CATALOG_COMMENT) { - onRefresh(); - } - } - - @Override - protected ActiveAdapter getListAdapter() { - return new ActiveAdapter(); - } - - @Override - protected String getCacheKeyPrefix() { - return new StringBuffer(CACHE_KEY_PREFIX + mCatalog).append( - AppContext.getInstance().getLoginUid()).toString(); - } - - @Override - protected ActiveList parseList(InputStream is) { - ActiveList list = XmlUtils.toBean(ActiveList.class, is); - return list; - } - - @Override - protected ActiveList readList(Serializable seri) { - return ((ActiveList) seri); - } - - @Override - public void initView(View view) { - if (mCatalog == ActiveList.CATALOG_LASTEST) { - setHasOptionsMenu(true); - } - super.initView(view); - mListView.setOnItemLongClickListener(this); - mListView.setOnItemClickListener(this); - mErrorLayout.setOnLayoutClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (AppContext.getInstance().isLogin()) { - mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING); - requestData(false); - } else { - UIHelper.showLoginActivity(getActivity()); - } - } - }); - if (AppContext.getInstance().isLogin()) { - UIHelper.sendBroadcastForNotice(getActivity()); - } - } - - @Override - protected void requestData(boolean refresh) { - if (AppContext.getInstance().isLogin()) { - mIsWatingLogin = false; - super.requestData(refresh); - } else { - mIsWatingLogin = true; - mErrorLayout.setErrorType(EmptyLayout.NETWORK_ERROR); - mErrorLayout.setErrorMessage(getString(R.string.unlogin_tip)); - } - } - - @Override - protected void sendRequestData() { - OSChinaApi.getActiveList(AppContext.getInstance().getLoginUid(), - mCatalog, mCurrentPage, mHandler); - } - - @Override - protected void onRefreshNetworkSuccess() { - if (AppContext.getInstance().isLogin()) { - if (0 == NoticeViewPagerFragment.sCurrentPage) { - NoticeUtils.clearNotice(Notice.TYPE_ATME); - } else if (1 == NoticeViewPagerFragment.sCurrentPage - || NoticeViewPagerFragment.sShowCount[1] > 0) { // 如果当前显示的是评论页,则发送评论页已被查看的Http请求 - NoticeUtils.clearNotice(Notice.TYPE_COMMENT); - } else { - NoticeUtils.clearNotice(Notice.TYPE_ATME); - } - UIHelper.sendBroadcastForNotice(getActivity()); - } - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, - long id) { - Active active = mAdapter.getItem(position); - if (active != null) - UIHelper.showActiveRedirect(view.getContext(), active); - } - - @Override - public boolean onItemLongClick(AdapterView parent, View view, - int position, long id) { - final Active active = mAdapter.getItem(position); - if (active == null) - return false; - String[] items = new String[] { getResources().getString(R.string.copy) }; - DialogHelp.getSelectDialog(getActivity(), items, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - TDevice.copyTextToBoard(HTMLUtil.delHTMLTag(active.getMessage())); - } - }).show(); - return true; - } - - @Override - protected long getAutoRefreshTime() { - // 最新动态,即是好友圈 - if (mCatalog == ActiveList.CATALOG_LASTEST) { - return 5 * 60; - } - return super.getAutoRefreshTime(); - } -} diff --git a/app/src/main/java/net/oschina/app/fragment/BlogDetailFragment.java b/app/src/main/java/net/oschina/app/fragment/BlogDetailFragment.java deleted file mode 100644 index 49a31ac2711b163731458bfb39062255904854a1..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/fragment/BlogDetailFragment.java +++ /dev/null @@ -1,133 +0,0 @@ -package net.oschina.app.fragment; - -import android.text.Editable; -import android.text.TextUtils; - -import net.oschina.app.AppContext; -import net.oschina.app.R; -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.base.CommonDetailFragment; -import net.oschina.app.bean.Blog; -import net.oschina.app.bean.BlogDetail; -import net.oschina.app.bean.CommentList; -import net.oschina.app.bean.FavoriteList; -import net.oschina.app.util.StringUtils; -import net.oschina.app.util.TDevice; -import net.oschina.app.util.ThemeSwitchUtils; -import net.oschina.app.util.UIHelper; -import net.oschina.app.util.URLsUtils; -import net.oschina.app.util.XmlUtils; - -import java.io.InputStream; - -/** - * Created by 火蚁 on 15/5/25. - */ -public class BlogDetailFragment extends CommonDetailFragment { - @Override - protected String getCacheKey() { - return "blog_" + mId; - } - - @Override - protected void sendRequestDataForNet() { - OSChinaApi.getBlogDetail(mId, mDetailHeandler); - } - - @Override - protected Blog parseData(InputStream is) { - return XmlUtils.toBean(BlogDetail.class, is).getBlog(); - } - - @Override - protected String getWebViewBody(Blog detail) { - StringBuffer body = new StringBuffer(); - body.append(UIHelper.WEB_STYLE).append(UIHelper.WEB_LOAD_IMAGES); - body.append(ThemeSwitchUtils.getWebViewBodyString()); - // 添加title - body.append(String.format("

%s
", mDetail.getTitle())); - // 添加作者和时间 - String time = StringUtils.friendly_time(mDetail.getPubDate()); - String author = String.format("%s", mDetail.getAuthorId(), mDetail.getAuthor()); - body.append(String.format("
%s    %s
", author, time)); - // 添加图片点击放大支持 - body.append(UIHelper.setHtmlCotentSupportImagePreview(mDetail.getBody())); - // 封尾 - body.append(""); - return body.toString(); - } - - @Override - protected void showCommentView() { - if (mDetail != null) { - UIHelper.showBlogComment(getActivity(), mId, - mDetail.getAuthorId()); - } - } - - @Override - protected int getCommentType() { - return CommentList.CATALOG_MESSAGE; - } - - @Override - protected String getShareTitle() { - return mDetail.getTitle(); - } - - @Override - protected String getShareContent() { - return StringUtils.getSubString(0, 55, - getFilterHtmlBody(mDetail.getBody())); - } - - @Override - protected String getShareUrl() { - return String.format(URLsUtils.URL_MOBILE + "blog/%s", mId); - } - - @Override - protected int getFavoriteTargetType() { - return FavoriteList.TYPE_BLOG; - } - - @Override - protected int getFavoriteState() { - return mDetail.getFavorite(); - } - - @Override - protected void updateFavoriteChanged(int newFavoritedState) { - mDetail.setFavorite(newFavoritedState); - saveCache(mDetail); - } - - @Override - protected int getCommentCount() { - return mDetail.getCommentCount(); - } - - @Override - public void onClickSendButton(Editable str) { - if (!TDevice.hasInternet()) { - AppContext.showToastShort(R.string.tip_network_error); - return; - } - if (!AppContext.getInstance().isLogin()) { - UIHelper.showLoginActivity(getActivity()); - return; - } - if (TextUtils.isEmpty(str)) { - AppContext.showToastShort(R.string.tip_comment_content_empty); - return; - } - showWaitDialog(R.string.progress_submit); - OSChinaApi.publicBlogComment(mId, AppContext.getInstance() - .getLoginUid(), str.toString(), mCommentHandler); - } - - @Override - protected String getRepotrUrl() { - return mDetail.getUrl(); - } -} diff --git a/app/src/main/java/net/oschina/app/fragment/BlogFragment.java b/app/src/main/java/net/oschina/app/fragment/BlogFragment.java deleted file mode 100644 index ebd209f7497911bd6085455eefc687e723be15ae..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/fragment/BlogFragment.java +++ /dev/null @@ -1,98 +0,0 @@ -package net.oschina.app.fragment; - -import java.io.InputStream; -import java.io.Serializable; - -import net.oschina.app.adapter.BlogAdapter; -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.base.BaseListFragment; -import net.oschina.app.bean.Blog; -import net.oschina.app.bean.BlogList; -import net.oschina.app.interf.OnTabReselectListener; -import net.oschina.app.util.UIHelper; -import net.oschina.app.util.XmlUtils; -import android.os.Bundle; -import android.view.View; -import android.widget.AdapterView; - -/** - * 博客区中单一模块的展示 - * - * @author kymjs(kymjs123@gmail.com) - */ -public class BlogFragment extends BaseListFragment implements - OnTabReselectListener { - - public static final String BUNDLE_BLOG_TYPE = "BUNDLE_BLOG_TYPE"; - - protected static final String TAG = BlogFragment.class.getSimpleName(); - private static final String CACHE_KEY_PREFIX = "bloglist_"; - - private String blogType; - - @Override - protected BlogAdapter getListAdapter() { - return new BlogAdapter(); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - Bundle args = getArguments(); - if (args != null) { - blogType = args.getString(BUNDLE_BLOG_TYPE); - } - } - - /** - * 获取当前展示页面的缓存数据 - */ - @Override - protected String getCacheKeyPrefix() { - return CACHE_KEY_PREFIX + blogType; - } - - @Override - protected BlogList parseList(InputStream is) throws Exception { - BlogList list = XmlUtils.toBean(BlogList.class, is); - return list; - } - - @Override - protected BlogList readList(Serializable seri) { - return ((BlogList) seri); - } - - @Override - protected void sendRequestData() { - OSChinaApi.getBlogList(blogType, mCurrentPage, mHandler); - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, - long id) { - Blog blog = mAdapter.getItem(position); - if (blog != null) { - UIHelper.showBlogDetail(getActivity(), blog.getId(), - blog.getCommentCount()); - // 保存到已读列表 - saveToReadedList(view, BlogList.PREF_READED_BLOG_LIST, blog.getId() - + ""); - } - } - - @Override - public void onTabReselect() { - onRefresh(); - } - - @Override - protected long getAutoRefreshTime() { - // TODO Auto-generated method stub - // 最新博客 - if (blogType.equals(BlogList.CATALOG_LATEST)) { - return 2 * 60 * 60; - } - return super.getAutoRefreshTime(); - } -} diff --git a/app/src/main/java/net/oschina/app/fragment/BrowserFragment.java b/app/src/main/java/net/oschina/app/fragment/BrowserFragment.java index 4fe858e6f11ba70ea852fece339b374802f12e49..eb17bcccde911fc319271584e8502b37722c09a8 100644 --- a/app/src/main/java/net/oschina/app/fragment/BrowserFragment.java +++ b/app/src/main/java/net/oschina/app/fragment/BrowserFragment.java @@ -6,6 +6,7 @@ import android.content.Intent; import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; +import android.support.v7.app.AlertDialog; import android.view.GestureDetector; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.LayoutInflater; @@ -29,37 +30,37 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ProgressBar; -import net.oschina.app.AppConfig; import net.oschina.app.AppContext; import net.oschina.app.R; import net.oschina.app.base.BaseActivity; import net.oschina.app.base.BaseFragment; -import net.oschina.app.ui.ShareDialog; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.dialog.ShareDialogBuilder; import net.oschina.app.ui.SimpleBackActivity; +import butterknife.Bind; import butterknife.ButterKnife; -import butterknife.InjectView; /** * 浏览器界面 - * + * * @author kymjs(kymjs123@gmail.com) */ @SuppressLint("NewApi") public class BrowserFragment extends BaseFragment { - @InjectView(R.id.webview) + @Bind(R.id.webview) WebView mWebView; - @InjectView(R.id.browser_back) + @Bind(R.id.browser_back) ImageView mImgBack; - @InjectView(R.id.browser_forward) + @Bind(R.id.browser_forward) ImageView mImgForward; - @InjectView(R.id.browser_refresh) + @Bind(R.id.browser_refresh) ImageView mImgRefresh; - @InjectView(R.id.browser_system_browser) + @Bind(R.id.browser_system_browser) ImageView mImgSystemBrowser; - @InjectView(R.id.browser_bottom) + @Bind(R.id.browser_bottom) LinearLayout mLayoutBottom; - @InjectView(R.id.progress) + @Bind(R.id.progress) ProgressBar mProgress; public static final String BROWSER_KEY = "browser_url"; @@ -72,29 +73,31 @@ public class BrowserFragment extends BaseFragment { private Animation animBottomIn, animBottomOut; private GestureDetector mGestureDetector; private CookieManager cookie; + private ShareDialogBuilder mShareDialogBuilder; + private AlertDialog alertDialog; @Override public void onClick(View v) { switch (v.getId()) { - case R.id.browser_back: - mWebView.goBack(); - break; - case R.id.browser_forward: - mWebView.goForward(); - break; - case R.id.browser_refresh: - mWebView.loadUrl(mWebView.getUrl()); - break; - case R.id.browser_system_browser: - try { - // 启用外部浏览器 - Uri uri = Uri.parse(mCurrentUrl); - Intent it = new Intent(Intent.ACTION_VIEW, uri); - aty.startActivity(it); - } catch (Exception e) { - AppContext.showToast("网页地址错误"); - } - break; + case R.id.browser_back: + mWebView.goBack(); + break; + case R.id.browser_forward: + mWebView.goForward(); + break; + case R.id.browser_refresh: + mWebView.loadUrl(mWebView.getUrl()); + break; + case R.id.browser_system_browser: + try { + // 启用外部浏览器 + Uri uri = Uri.parse(mCurrentUrl); + Intent it = new Intent(Intent.ACTION_VIEW, uri); + aty.startActivity(it); + } catch (Exception e) { + AppContext.showToast("网页地址错误"); + } + break; } } @@ -121,6 +124,11 @@ public class BrowserFragment extends BaseFragment { public void onResume() { super.onResume(); mWebView.onResume(); + + if (mShareDialogBuilder != null) { + mShareDialogBuilder.cancelLoading(); + } + } @Override @@ -146,12 +154,12 @@ public class BrowserFragment extends BaseFragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { + Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); View rootView = inflater.inflate(R.layout.fragment_browser, container, false); aty = getActivity(); - ButterKnife.inject(this, rootView); + ButterKnife.bind(this, rootView); initData(); initView(rootView); return rootView; @@ -171,9 +179,9 @@ public class BrowserFragment extends BaseFragment { @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case R.id.public_menu_shared: - showSharedDialog(); - break; + case R.id.public_menu_shared: + showSharedDialog(); + break; } return true; } @@ -187,10 +195,12 @@ public class BrowserFragment extends BaseFragment { R.anim.anim_bottom_out); animBottomIn.setAnimationListener(new AnimationListener() { @Override - public void onAnimationStart(Animation animation) {} + public void onAnimationStart(Animation animation) { + } @Override - public void onAnimationRepeat(Animation animation) {} + public void onAnimationRepeat(Animation animation) { + } @Override public void onAnimationEnd(Animation animation) { @@ -199,10 +209,12 @@ public class BrowserFragment extends BaseFragment { }); animBottomOut.setAnimationListener(new AnimationListener() { @Override - public void onAnimationStart(Animation animation) {} + public void onAnimationStart(Animation animation) { + } @Override - public void onAnimationRepeat(Animation animation) {} + public void onAnimationRepeat(Animation animation) { + } @Override public void onAnimationEnd(Animation animation) { @@ -215,35 +227,35 @@ public class BrowserFragment extends BaseFragment { * 打开分享dialog */ private void showSharedDialog() { - final ShareDialog dialog = new ShareDialog(getActivity()); - dialog.setCancelable(true); - dialog.setCanceledOnTouchOutside(true); - dialog.setTitle(R.string.share_to); - dialog.setShareInfo(getShareTitle(), getShareContent(), mCurrentUrl); - dialog.show(); + if (mShareDialogBuilder == null) { + mShareDialogBuilder = ShareDialogBuilder.with(getActivity()) + .title(getShareTitle()) + .content(getShareContent()) + .url(mCurrentUrl) + .build(); + } + if (alertDialog == null) + alertDialog = mShareDialogBuilder.create(); + alertDialog.show(); } + /** * 载入链接之前会被调用 - * - * @param view - * WebView - * @param url - * 链接地址 + * + * @param view WebView + * @param url 链接地址 */ protected void onUrlLoading(WebView view, String url) { mProgress.setVisibility(View.VISIBLE); - cookie.setCookie(url, - AppContext.getInstance().getProperty(AppConfig.CONF_COOKIE)); + cookie.setCookie(url, AccountHelper.getCookie()); } /** * 链接载入成功后会被调用 - * - * @param view - * WebView - * @param url - * 链接地址 + * + * @param view WebView + * @param url 链接地址 */ protected void onUrlFinished(WebView view, String url) { mCurrentUrl = url; @@ -252,11 +264,9 @@ public class BrowserFragment extends BaseFragment { /** * 当前WebView显示页面的标题 - * - * @param view - * WebView - * @param title - * web页面标题 + * + * @param view WebView + * @param title web页面标题 */ protected void onWebTitle(WebView view, String title) { if (aty != null && mWebView != null) { // 必须做判断,由于webview加载属于耗时操作,可能会本Activity已经关闭了才被调用 @@ -266,13 +276,12 @@ public class BrowserFragment extends BaseFragment { /** * 当前WebView显示页面的图标 - * - * @param view - * WebView - * @param icon - * web页面图标 + * + * @param view WebView + * @param icon web页面图标 */ - protected void onWebIcon(WebView view, Bitmap icon) {} + protected void onWebIcon(WebView view, Bitmap icon) { + } /** * 初始化浏览器设置信息 diff --git a/app/src/main/java/net/oschina/app/fragment/CommentFrament.java b/app/src/main/java/net/oschina/app/fragment/CommentFrament.java deleted file mode 100644 index 1667c7196c6dc00c8e27397b36bb1e6e0b1df0e7..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/fragment/CommentFrament.java +++ /dev/null @@ -1,337 +0,0 @@ -package net.oschina.app.fragment; - -import android.app.Activity; -import android.content.DialogInterface; -import android.content.Intent; -import android.os.Bundle; -import android.text.Editable; -import android.text.TextUtils; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.WindowManager; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemLongClickListener; - -import com.loopj.android.http.AsyncHttpResponseHandler; - -import net.oschina.app.AppContext; -import net.oschina.app.R; -import net.oschina.app.adapter.CommentAdapter; -import net.oschina.app.api.OperationResponseHandler; -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.base.BaseActivity; -import net.oschina.app.base.BaseListFragment; -import net.oschina.app.bean.BlogCommentList; -import net.oschina.app.bean.Comment; -import net.oschina.app.bean.CommentList; -import net.oschina.app.bean.ListEntity; -import net.oschina.app.bean.Result; -import net.oschina.app.bean.ResultBean; -import net.oschina.app.emoji.OnSendClickListener; -import net.oschina.app.ui.DetailActivity; -import net.oschina.app.util.DialogHelp; -import net.oschina.app.util.HTMLUtil; -import net.oschina.app.util.TDevice; -import net.oschina.app.util.UIHelper; -import net.oschina.app.util.XmlUtils; - -import cz.msebera.android.httpclient.Header; -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.io.Serializable; - -public class CommentFrament extends BaseListFragment implements - OnItemLongClickListener, OnSendClickListener { - - public static final String BUNDLE_KEY_CATALOG = "BUNDLE_KEY_CATALOG"; - public static final String BUNDLE_KEY_BLOG = "BUNDLE_KEY_BLOG"; - public static final String BUNDLE_KEY_ID = "BUNDLE_KEY_ID"; - public static final String BUNDLE_KEY_OWNER_ID = "BUNDLE_KEY_OWNER_ID"; - protected static final String TAG = CommentFrament.class.getSimpleName(); - private static final String BLOG_CACHE_KEY_PREFIX = "blogcomment_list"; - private static final String CACHE_KEY_PREFIX = "comment_list"; - private static final int REQUEST_CODE = 0x10; - - private int mId, mOwnerId; - private boolean mIsBlogComment; - private DetailActivity outAty; - - private final AsyncHttpResponseHandler mCommentHandler = new AsyncHttpResponseHandler() { - - @Override - public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { - try { - ResultBean rsb = XmlUtils.toBean(ResultBean.class, - new ByteArrayInputStream(arg2)); - Result res = rsb.getResult(); - if (res.OK()) { - hideWaitDialog(); - AppContext.showToastShort(R.string.comment_publish_success); - - mAdapter.addItem(0, rsb.getComment()); - mAdapter.notifyDataSetChanged(); - UIHelper.sendBroadCastCommentChanged(getActivity(), - mIsBlogComment, mId, mCatalog, Comment.OPT_ADD, - rsb.getComment()); - onRefresh(); - outAty.emojiFragment.clean(); - } else { - hideWaitDialog(); - AppContext.showToastShort(res.getErrorMessage()); - } - } catch (Exception e) { - e.printStackTrace(); - onFailure(arg0, arg1, arg2, e); - } - } - - @Override - public void onFailure(int arg0, Header[] arg1, byte[] arg2, - Throwable arg3) { - hideWaitDialog(); - AppContext.showToastShort(R.string.comment_publish_faile); - } - }; - - @Override - public void initView(View view) { - super.initView(view); - mListView.setOnItemLongClickListener(this); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - outAty = (DetailActivity) getActivity(); - return super.onCreateView(inflater, container, savedInstanceState); - } - - @Override - public void onCreate(android.os.Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - Bundle args = getActivity().getIntent().getExtras(); - if (args != null) { - mCatalog = args.getInt(BUNDLE_KEY_CATALOG, 0); - mId = args.getInt(BUNDLE_KEY_ID, 0); - mOwnerId = args.getInt(BUNDLE_KEY_OWNER_ID, 0); - mIsBlogComment = args.getBoolean(BUNDLE_KEY_BLOG, false); - } - - if (!mIsBlogComment && mCatalog == CommentList.CATALOG_POST) { - ((BaseActivity) getActivity()) - .setActionBarTitle(R.string.post_answer); - } - - int mode = WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN - | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; - getActivity().getWindow().setSoftInputMode(mode); - } - - @Override - public void onResume() { - super.onResume(); - outAty.emojiFragment.hideFlagButton(); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (requestCode == REQUEST_CODE && resultCode == Activity.RESULT_OK) { - Comment comment = data - .getParcelableExtra(Comment.BUNDLE_KEY_COMMENT); - if (comment != null) { - mAdapter.addItem(0, comment); - } - } - super.onActivityResult(requestCode, resultCode, data); - } - - @Override - protected CommentAdapter getListAdapter() { - return new CommentAdapter(); - } - - @Override - protected String getCacheKeyPrefix() { - String str = mIsBlogComment ? BLOG_CACHE_KEY_PREFIX : CACHE_KEY_PREFIX; - return new StringBuilder(str).append("_").append(mId).append("_Owner") - .append(mOwnerId).toString(); - } - - @Override - protected ListEntity parseList(InputStream is) throws Exception { - if (mIsBlogComment) { - return XmlUtils.toBean(BlogCommentList.class, is); - } else { - return XmlUtils.toBean(CommentList.class, is); - } - } - - @Override - protected ListEntity readList(Serializable seri) { - if (mIsBlogComment) - return ((BlogCommentList) seri); - return ((CommentList) seri); - } - - @Override - protected void sendRequestData() { - if (mIsBlogComment) { - OSChinaApi.getBlogCommentList(mId, mCurrentPage, mHandler); - } else { - OSChinaApi.getCommentList(mId, mCatalog, mCurrentPage, mHandler); - } - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, - long id) { - final Comment comment = mAdapter.getItem(position); - if (comment == null) - return; - outAty.emojiFragment.getEditText().setTag(comment); - outAty.emojiFragment.getEditText().setHint("回复:" + comment.getAuthor()); - outAty.emojiFragment.showSoftKeyboard(); - } - - private void handleDeleteComment(Comment comment) { - if (!AppContext.getInstance().isLogin()) { - UIHelper.showLoginActivity(getActivity()); - return; - } - AppContext.showToastShort(R.string.deleting); - if (mIsBlogComment) { - OSChinaApi.deleteBlogComment( - AppContext.getInstance().getLoginUid(), mId, - comment.getId(), comment.getAuthorId(), mOwnerId, - new DeleteOperationResponseHandler(comment)); - } else { - OSChinaApi - .deleteComment(mId, mCatalog, comment.getId(), - comment.getAuthorId(), - new DeleteOperationResponseHandler(comment)); - } - } - - class DeleteOperationResponseHandler extends OperationResponseHandler { - - DeleteOperationResponseHandler(Object... args) { - super(args); - } - - @Override - public void onSuccess(int code, ByteArrayInputStream is, Object[] args) { - try { - Result res = XmlUtils.toBean(ResultBean.class, is).getResult(); - if (res.OK()) { - AppContext.showToastShort(R.string.delete_success); - mAdapter.removeItem(args[0]); - } else { - AppContext.showToastShort(res.getErrorMessage()); - } - } catch (Exception e) { - e.printStackTrace(); - onFailure(code, e.getMessage(), args); - } - } - - @Override - public void onFailure(int code, String errorMessage, Object[] args) { - AppContext.showToastShort(R.string.delete_faile); - } - } - - @Override - public boolean onItemLongClick(AdapterView parent, View view, - int position, long id) { - final Comment item = mAdapter.getItem(position); - if (item == null) - return false; - int itemsLen = item.getAuthorId() == AppContext.getInstance() - .getLoginUid() ? 2 : 1; - String[] items = new String[itemsLen]; - items[0] = getResources().getString(R.string.copy); - if (itemsLen == 2) { - items[1] = getResources().getString(R.string.delete); - } - DialogHelp.getSelectDialog(getActivity(), items, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (i == 0) { - TDevice.copyTextToBoard(HTMLUtil.delHTMLTag(item - .getContent())); - } else if (i == 1) { - handleDeleteComment(item); - } - } - }).show(); - return true; - } - - @Override - public void onClickSendButton(Editable text) { - if (!TDevice.hasInternet()) { - AppContext.showToastShort(R.string.tip_network_error); - return; - } - if (TextUtils.isEmpty(text)) { - AppContext.showToastShort(R.string.tip_comment_content_empty); - return; - } - if (!AppContext.getInstance().isLogin()) { - UIHelper.showLoginActivity(getActivity()); - return; - } - if (outAty.emojiFragment.getEditText().getTag() != null) { - handleReplyComment((Comment) outAty.emojiFragment.getEditText().getTag(), - text.toString()); - } else { - sendReply(text.toString()); - } - } - - private void sendReply(String text) { - showWaitDialog(R.string.progress_submit); - if (mIsBlogComment) { - OSChinaApi.publicBlogComment(mId, AppContext.getInstance() - .getLoginUid(), text, mCommentHandler); - } else { - OSChinaApi.publicComment(mCatalog, mId, AppContext.getInstance() - .getLoginUid(), text, 1, mCommentHandler); - } - } - - private void handleReplyComment(Comment comment, String text) { - showWaitDialog(R.string.progress_submit); - if (!AppContext.getInstance().isLogin()) { - UIHelper.showLoginActivity(getActivity()); - return; - } - if (mIsBlogComment) { - OSChinaApi.replyBlogComment(mId, AppContext.getInstance() - .getLoginUid(), text, comment.getId(), comment - .getAuthorId(), mCommentHandler); - } else { - OSChinaApi.replyComment(mId, mCatalog, comment.getId(), comment - .getAuthorId(), AppContext.getInstance().getLoginUid(), - text, mCommentHandler); - } - } - - @Override - public boolean onBackPressed() { - if (outAty.emojiFragment.isShowEmojiKeyBoard()) { - outAty.emojiFragment.hideAllKeyBoard(); - return true; - } - if (outAty.emojiFragment.getEditText().getTag() != null) { - outAty.emojiFragment.getEditText().setTag(null); - outAty.emojiFragment.getEditText().setHint("说点什么吧"); - return true; - } - return super.onBackPressed(); - } - - @Override - public void onClickFlagButton() {} -} diff --git a/app/src/main/java/net/oschina/app/fragment/EventAppliesFragment.java b/app/src/main/java/net/oschina/app/fragment/EventAppliesFragment.java index d7ce33c2b08d3e9ba12c419f89d9945afb8eb323..4ceaaa9ae39f32f29edecc97bb7b3e1180d7fb1f 100644 --- a/app/src/main/java/net/oschina/app/fragment/EventAppliesFragment.java +++ b/app/src/main/java/net/oschina/app/fragment/EventAppliesFragment.java @@ -1,20 +1,21 @@ package net.oschina.app.fragment; -import java.io.InputStream; -import java.io.Serializable; +import android.annotation.TargetApi; +import android.os.Build; +import android.view.View; +import android.widget.AdapterView; -import net.oschina.app.AppContext; import net.oschina.app.adapter.EventApplyAdapter; import net.oschina.app.api.remote.OSChinaApi; import net.oschina.app.base.BaseListFragment; import net.oschina.app.bean.Apply; import net.oschina.app.bean.EventAppliesList; +import net.oschina.app.improve.account.AccountHelper; import net.oschina.app.util.UIHelper; import net.oschina.app.util.XmlUtils; -import android.annotation.TargetApi; -import android.os.Build; -import android.view.View; -import android.widget.AdapterView; + +import java.io.InputStream; +import java.io.Serializable; /** * 活动出席人员列表 @@ -46,8 +47,7 @@ public class EventAppliesFragment extends BaseListFragment { @Override protected EventAppliesList parseList(InputStream is) throws Exception { - EventAppliesList list = XmlUtils.toBean(EventAppliesList.class, is); - return list; + return XmlUtils.toBean(EventAppliesList.class, is); } @Override @@ -63,9 +63,9 @@ public class EventAppliesFragment extends BaseListFragment { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { - Apply item = (Apply) mAdapter.getItem(position); + Apply item = mAdapter.getItem(position); if (item != null) { - if (AppContext.getInstance().isLogin()) { + if (AccountHelper.isLogin()) { UIHelper.showMessageDetail(getActivity(), item.getId(), item.getName()); return; } diff --git a/app/src/main/java/net/oschina/app/fragment/EventDetailFragment.java b/app/src/main/java/net/oschina/app/fragment/EventDetailFragment.java deleted file mode 100644 index 60262d4bc1eb1da490fca42be34c4d301a2052d0..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/fragment/EventDetailFragment.java +++ /dev/null @@ -1,322 +0,0 @@ -package net.oschina.app.fragment; - -import android.content.DialogInterface; -import android.os.Bundle; -import android.view.View; -import android.widget.Button; -import android.widget.TextView; - -import com.loopj.android.http.AsyncHttpResponseHandler; - -import net.oschina.app.AppContext; -import net.oschina.app.R; -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.base.BaseListFragment; -import net.oschina.app.base.CommonDetailFragment; -import net.oschina.app.bean.CommentList; -import net.oschina.app.bean.Event; -import net.oschina.app.bean.EventApplyData; -import net.oschina.app.bean.FavoriteList; -import net.oschina.app.bean.Post; -import net.oschina.app.bean.PostDetail; -import net.oschina.app.bean.Result; -import net.oschina.app.bean.ResultBean; -import net.oschina.app.bean.SimpleBackPage; -import net.oschina.app.ui.EventApplyDialog; -import net.oschina.app.util.StringUtils; -import net.oschina.app.util.ThemeSwitchUtils; -import net.oschina.app.util.UIHelper; -import net.oschina.app.util.URLsUtils; -import net.oschina.app.util.XmlUtils; - -import cz.msebera.android.httpclient.Header; -import java.io.ByteArrayInputStream; -import java.io.InputStream; - -import butterknife.InjectView; - -/** - * Created by 火蚁 on 15/5/28. - */ -public class EventDetailFragment extends CommonDetailFragment { - - @InjectView(R.id.tv_event_title) - TextView mTvTitle; - - @InjectView(R.id.tv_event_start_time) - TextView mTvStartTime; - - @InjectView(R.id.tv_event_end_time) - TextView mTvEndTime; - - @InjectView(R.id.tv_event_spot) - TextView mTvSpot; - - @InjectView(R.id.rl_event_location) - View mLocation; - - @InjectView(R.id.bt_event_attend) - Button mBtAttend;// 出席人员 - - @InjectView(R.id.bt_event_apply) - Button mBtEventApply;// 活动报名 - - @InjectView(R.id.tv_event_tip) - TextView mEventTip; - - private EventApplyDialog mEventApplyDialog; - - @Override - public void initView(View view) { - super.initView(view); - mLocation.setOnClickListener(this); - mBtAttend.setOnClickListener(this); - mBtEventApply.setOnClickListener(this); - } - - @Override - protected int getLayoutId() { - return R.layout.fragment_event_detail; - } - - @Override - protected String getCacheKey() { - return "post_" + mId; - } - - @Override - protected void sendRequestDataForNet() { - OSChinaApi.getPostDetail(mId, mDetailHeandler); - } - - @Override - protected Post parseData(InputStream is) { - return XmlUtils.toBean(PostDetail.class, is).getPost(); - } - - @Override - protected String getWebViewBody(Post detail) { - StringBuffer body = new StringBuffer(); - body.append(UIHelper.WEB_STYLE).append(UIHelper.WEB_LOAD_IMAGES); - body.append(ThemeSwitchUtils.getWebViewBodyString()); - // 添加title - body.append(String.format("
%s
", mDetail.getTitle())); - // 添加作者和时间 - String time = StringUtils.friendly_time(mDetail.getPubDate()); - String author = String.format("%s", mDetail.getAuthorId(), mDetail.getAuthor()); - body.append(String.format("
%s    %s
", author, time)); - // 添加图片点击放大支持 - body.append(UIHelper.setHtmlCotentSupportImagePreview(mDetail.getBody())); - // 封尾 - body.append(""); - return body.toString(); - } - - @Override - protected void executeOnLoadDataSuccess(Post detail) { - super.executeOnLoadDataSuccess(detail); - mTvTitle.setText(mDetail.getTitle()); - mTvStartTime.setText(String.format( - getString(R.string.event_start_time), mDetail.getEvent() - .getStartTime())); - mTvEndTime.setText(String.format(getString(R.string.event_end_time), - mDetail.getEvent().getEndTime())); - mTvSpot.setText(mDetail.getEvent().getCity() + " " - + mDetail.getEvent().getSpot()); - - // 站外活动 - if (mDetail.getEvent().getCategory() == 4) { - mBtEventApply.setVisibility(View.VISIBLE); - mBtAttend.setVisibility(View.GONE); - mBtEventApply.setText("报名链接"); - } else { - notifyEventStatus(); - } - } - - // 显示活动 以及报名的状态 - private void notifyEventStatus() { - int eventStatus = mDetail.getEvent().getStatus(); - int applyStatus = mDetail.getEvent().getApplyStatus(); - - if (applyStatus == Event.APPLYSTATUS_ATTEND) { - mBtAttend.setVisibility(View.VISIBLE); - } else { - mBtAttend.setVisibility(View.GONE); - } - - if (eventStatus == Event.EVNET_STATUS_APPLYING) { - mBtEventApply.setVisibility(View.VISIBLE); - mBtEventApply.setEnabled(false); - switch (applyStatus) { - case Event.APPLYSTATUS_CHECKING: - mBtEventApply.setText("待确认"); - break; - case Event.APPLYSTATUS_CHECKED: - mBtEventApply.setText("已确认"); - mBtEventApply.setVisibility(View.GONE); - mEventTip.setVisibility(View.VISIBLE); - break; - case Event.APPLYSTATUS_ATTEND: - mBtEventApply.setText("已出席"); - break; - case Event.APPLYSTATUS_CANCLE: - mBtEventApply.setText("已取消"); - mBtEventApply.setEnabled(true); - break; - case Event.APPLYSTATUS_REJECT: - mBtEventApply.setText("已拒绝"); - break; - default: - mBtEventApply.setText("我要报名"); - mBtEventApply.setEnabled(true); - break; - } - } else { - mBtEventApply.setVisibility(View.GONE); - } - } - - @Override - protected void showCommentView() { - if (mDetail != null) { - UIHelper.showComment(getActivity(), mId, CommentList.CATALOG_POST); - } - } - - @Override - protected int getCommentType() { - return CommentList.CATALOG_POST; - } - - @Override - protected int getFavoriteTargetType() { - return FavoriteList.TYPE_POST; - } - - @Override - protected int getFavoriteState() { - return mDetail.getFavorite(); - } - - @Override - protected void updateFavoriteChanged(int newFavoritedState) { - mDetail.setFavorite(newFavoritedState); - saveCache(mDetail); - } - - @Override - protected int getCommentCount() { - return mDetail.getAnswerCount(); - } - - @Override - public void onClick(View v) { - int id = v.getId(); - switch (id) { - case R.id.rl_event_location: - UIHelper.showEventLocation(getActivity(), mDetail.getEvent() - .getCity(), mDetail.getEvent().getSpot()); - break; - case R.id.bt_event_attend: - showEventApplies(); - break; - case R.id.bt_event_apply: - showEventApply(); - break; - default: - break; - } - } - - private void showEventApplies() { - Bundle args = new Bundle(); - args.putInt(BaseListFragment.BUNDLE_KEY_CATALOG, mDetail.getEvent() - .getId()); - UIHelper.showSimpleBack(getActivity(), SimpleBackPage.EVENT_APPLY, args); - } - - private final AsyncHttpResponseHandler mApplyHandler = new AsyncHttpResponseHandler() { - - @Override - public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { - Result rs = XmlUtils.toBean(ResultBean.class, - new ByteArrayInputStream(arg2)).getResult(); - if (rs.OK()) { - AppContext.showToast("报名成功"); - mEventApplyDialog.dismiss(); - mDetail.getEvent().setApplyStatus(Event.APPLYSTATUS_CHECKING); - } else { - AppContext.showToast(rs.getErrorMessage()); - } - } - - @Override - public void onFailure(int arg0, Header[] arg1, byte[] arg2, - Throwable arg3) { - AppContext.showToast("报名失败"); - } - - @Override - public void onFinish() { - hideWaitDialog(); - } - }; - - /** - * 显示活动报名对话框 - */ - private void showEventApply() { - - if (mDetail.getEvent().getCategory() == 4) { - UIHelper.openSysBrowser(getActivity(), mDetail.getEvent().getUrl()); - return; - } - - if (!AppContext.getInstance().isLogin()) { - UIHelper.showLoginActivity(getActivity()); - return; - } - if (mEventApplyDialog == null) { - mEventApplyDialog = new EventApplyDialog(getActivity(), mDetail.getEvent()); - mEventApplyDialog.setCanceledOnTouchOutside(true); - mEventApplyDialog.setCancelable(true); - mEventApplyDialog.setTitle("活动报名"); - mEventApplyDialog.setCanceledOnTouchOutside(true); - mEventApplyDialog.setNegativeButton(R.string.cancle, null); - mEventApplyDialog.setPositiveButton(R.string.ok, - new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface d, int which) { - EventApplyData data = null; - if ((data = mEventApplyDialog.getApplyData()) != null) { - data.setEvent(mId); - data.setUser(AppContext.getInstance() - .getLoginUid()); - showWaitDialog(R.string.progress_submit); - OSChinaApi.eventApply(data, mApplyHandler); - } - } - }); - } - - mEventApplyDialog.show(); - } - - @Override - protected String getShareTitle() { - return mDetail.getTitle(); - } - - @Override - protected String getShareContent() { - return StringUtils.getSubString(0, 55, - getFilterHtmlBody(mDetail.getBody())); - } - - @Override - protected String getShareUrl() { - return String.format(URLsUtils.URL_MOBILE + "question/%s_%s", mDetail.getAuthorId(), mId); - } -} diff --git a/app/src/main/java/net/oschina/app/fragment/EventFragment.java b/app/src/main/java/net/oschina/app/fragment/EventFragment.java index 8e8c6d5911e892336ac46c916376f7e1bdd9b762..683cf3b114820642f3a8d170f4f39300fa4c6464 100644 --- a/app/src/main/java/net/oschina/app/fragment/EventFragment.java +++ b/app/src/main/java/net/oschina/app/fragment/EventFragment.java @@ -1,9 +1,13 @@ package net.oschina.app.fragment; -import java.io.InputStream; -import java.io.Serializable; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Bundle; +import android.view.View; +import android.widget.AdapterView; -import net.oschina.app.AppContext; import net.oschina.app.R; import net.oschina.app.adapter.EventAdapter; import net.oschina.app.api.remote.OSChinaApi; @@ -11,29 +15,24 @@ import net.oschina.app.base.BaseListFragment; import net.oschina.app.bean.Constants; import net.oschina.app.bean.Event; import net.oschina.app.bean.EventList; +import net.oschina.app.improve.account.AccountHelper; import net.oschina.app.ui.empty.EmptyLayout; import net.oschina.app.util.UIHelper; import net.oschina.app.util.XmlUtils; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Bundle; -import android.view.View; -import android.widget.AdapterView; + +import java.io.InputStream; +import java.io.Serializable; /** * 活动列表fragment - * + * * @author FireAnt(http://my.oschina.net/LittleDY) * @version 创建时间:2014年12月8日 下午5:17:32 - * */ public class EventFragment extends BaseListFragment { public static final String BUNDLE_KEY_EVENT_TYPE = "eventlist_type"; - protected static final String TAG = EventFragment.class.getSimpleName(); private static final String CACHE_KEY_PREFIX = "eventlist_"; private int event_type; @@ -94,7 +93,7 @@ public class EventFragment extends BaseListFragment { mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING); requestData(true); } else { - if (AppContext.getInstance().isLogin()) { + if (AccountHelper.isLogin()) { mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING); requestData(true); } else { @@ -111,8 +110,8 @@ public class EventFragment extends BaseListFragment { super.requestData(refresh); return; } - if (AppContext.getInstance().isLogin()) { - mCatalog = AppContext.getInstance().getLoginUid(); + if (AccountHelper.isLogin()) { + mCatalog = (int) AccountHelper.getUserId(); super.requestData(refresh); } else { mErrorLayout.setErrorType(EmptyLayout.NETWORK_ERROR); @@ -127,8 +126,7 @@ public class EventFragment extends BaseListFragment { @Override protected EventList parseList(InputStream is) throws Exception { - EventList list = XmlUtils.toBean(EventList.class, is); - return list; + return XmlUtils.toBean(EventList.class, is); } @Override @@ -143,7 +141,7 @@ public class EventFragment extends BaseListFragment { @Override public void onItemClick(AdapterView parent, View view, int position, - long id) { + long id) { Event event = mAdapter.getItem(position); if (event != null) UIHelper.showEventDetail(view.getContext(), event.getId()); diff --git a/app/src/main/java/net/oschina/app/fragment/ExploreFragment.java b/app/src/main/java/net/oschina/app/fragment/ExploreFragment.java deleted file mode 100644 index e8bc09ddd88ba7c5e3d1b1c0a0442b3142febc1d..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/fragment/ExploreFragment.java +++ /dev/null @@ -1,111 +0,0 @@ -package net.oschina.app.fragment; - -import android.content.Intent; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import net.oschina.app.R; -import net.oschina.app.base.BaseFragment; -import net.oschina.app.bean.SimpleBackPage; -import net.oschina.app.ui.FindUserActivity; -import net.oschina.app.ui.ShakeActivity; -import net.oschina.app.util.UIHelper; - -import butterknife.ButterKnife; -import butterknife.InjectView; - -/** - * 发现页面 - * - * @author FireAnt(http://my.oschina.net/LittleDY) - * @version 创建时间:2014年11月4日 下午3:34:07 - * - */ - -public class ExploreFragment extends BaseFragment { - - @InjectView(R.id.rl_active) - View mRlActive; - - @InjectView(R.id.rl_find_osc) - View mFindOSCer; - - @InjectView(R.id.rl_city) - View mCity; - - @InjectView(R.id.rl_activities) - View mActivities; - - @InjectView(R.id.rl_scan) - View mScan; - - @InjectView(R.id.rl_shake) - View mShake; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - super.onCreateView(inflater, container, savedInstanceState); - View view = inflater.inflate(R.layout.fragment_explore, null); - ButterKnife.inject(this, view); - initView(view); - return view; - } - - @Override - public void onClick(View v) { - int id = v.getId(); - switch (id) { - case R.id.rl_active: - UIHelper.showMyActive(getActivity()); - break; - case R.id.rl_find_osc: - showFindUser(); - break; - case R.id.rl_city: - UIHelper.showSimpleBack(getActivity(), SimpleBackPage.SAME_CITY); - break; - case R.id.rl_activities: - UIHelper.showSimpleBack(getActivity(), SimpleBackPage.EVENT_LIST); - break; - case R.id.rl_scan: - UIHelper.showScanActivity(getActivity()); - break; - case R.id.rl_shake: - showShake(); - break; - default: - break; - } - } - - private void showShake() { - Intent intent = new Intent(); - intent.setClass(getActivity(), ShakeActivity.class); - getActivity().startActivity(intent); - } - - private void showFindUser() { - Intent intent = new Intent(); - intent.setClass(getActivity(), FindUserActivity.class); - getActivity().startActivity(intent); - } - - @Override - public void initView(View view) { - mRlActive.setOnClickListener(this); - - mFindOSCer.setOnClickListener(this); - mCity.setOnClickListener(this); - mActivities.setOnClickListener(this); - mScan.setOnClickListener(this); - mShake.setOnClickListener(this); - } - - @Override - public void initData() { - - } -} diff --git a/app/src/main/java/net/oschina/app/fragment/FeedBackFragment.java b/app/src/main/java/net/oschina/app/fragment/FeedBackFragment.java deleted file mode 100644 index a6f5e403f117c1d24837b918efed9852ffe0bd68..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/fragment/FeedBackFragment.java +++ /dev/null @@ -1,96 +0,0 @@ -package net.oschina.app.fragment; - -import net.oschina.app.AppContext; -import net.oschina.app.R; -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.base.BaseFragment; -import net.oschina.app.util.StringUtils; -import net.oschina.app.util.TDevice; - -import cz.msebera.android.httpclient.Header; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.EditText; -import butterknife.ButterKnife; -import butterknife.InjectView; - -import com.loopj.android.http.AsyncHttpResponseHandler; - -public class FeedBackFragment extends BaseFragment { - @InjectView(R.id.et_feedback) - EditText mEtContent; - @InjectView(R.id.et_contact) - EditText mEtContact; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - super.onCreateView(inflater, container, savedInstanceState); - View view = inflater.inflate(R.layout.fragment_feedback, null); - ButterKnife.inject(this, view); - initView(view); - return view; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setHasOptionsMenu(true); - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - inflater.inflate(R.menu.submit_menu, menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.public_menu_send: - String data = mEtContent.getText().toString(); - if (StringUtils.isEmpty(data)) { - AppContext.showToast("你忘记写建议咯"); - } else { - data += "
"; - data += mEtContact.getText() + "
"; - data += TDevice.getVersionName() + "(" - + TDevice.getVersionCode() + ")
"; - OSChinaApi.feedback(data, new AsyncHttpResponseHandler() { - @Override - public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { - AppContext.showToast("已收到你的建议,谢谢"); - getActivity().finish(); - } - - @Override - public void onFailure(int arg0, Header[] arg1, byte[] arg2, - Throwable arg3) { - AppContext.showToast("网络异常,请稍后重试"); - } - }); - } - break; - } - return true; - } - - @Override - public void onClick(View v) { - - } - - @Override - public void initView(View view) { - - } - - @Override - public void initData() { - - } -} diff --git a/app/src/main/java/net/oschina/app/fragment/FriendsFragment.java b/app/src/main/java/net/oschina/app/fragment/FriendsFragment.java deleted file mode 100644 index 9a84cd48dfdb7b89d152890c7727fb4e72b84469..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/fragment/FriendsFragment.java +++ /dev/null @@ -1,137 +0,0 @@ -package net.oschina.app.fragment; - -import java.io.InputStream; -import java.io.Serializable; -import java.util.List; - -import net.oschina.app.AppContext; -import net.oschina.app.adapter.FriendAdapter; -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.base.BaseListFragment; -import net.oschina.app.bean.Entity; -import net.oschina.app.bean.Friend; -import net.oschina.app.bean.FriendsList; -import net.oschina.app.bean.Notice; -import net.oschina.app.service.NoticeUtils; -import net.oschina.app.ui.MainActivity; -import net.oschina.app.util.UIHelper; -import net.oschina.app.util.XmlUtils; -import net.oschina.app.viewpagerfragment.NoticeViewPagerFragment; -import android.annotation.TargetApi; -import android.os.Build; -import android.os.Bundle; -import android.view.View; -import android.widget.AdapterView; - -/** - * 关注、粉丝 - * - * @author FireAnt(http://my.oschina.net/LittleDY) - * @created 2014年11月6日 上午11:15:37 - * - */ -@TargetApi(Build.VERSION_CODES.HONEYCOMB) -public class FriendsFragment extends BaseListFragment { - - public final static String BUNDLE_KEY_UID = "UID"; - - protected static final String TAG = FriendsFragment.class.getSimpleName(); - private static final String CACHE_KEY_PREFIX = "friend_list"; - - private int mUid; - - @Override - public void initView(View view) { - super.initView(view); - } - - @Override - public void onCreate(android.os.Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - Bundle args = getArguments(); - if (args != null) { - mUid = args.getInt(BUNDLE_KEY_UID, 0); - } - } - - @Override - public void onResume() { - if (mCatalog == FriendsList.TYPE_FANS - && mUid == AppContext.getInstance().getLoginUid()) { - refreshNotice(); - } - super.onResume(); - } - - private void refreshNotice() { - Notice notice = MainActivity.mNotice; - if (notice != null && notice.getNewFansCount() > 0) { - onRefresh(); - } - } - - @Override - protected FriendAdapter getListAdapter() { - return new FriendAdapter(); - } - - @Override - protected String getCacheKeyPrefix() { - return CACHE_KEY_PREFIX + "_" + mCatalog + "_" + mUid; - } - - @Override - protected FriendsList parseList(InputStream is) throws Exception { - FriendsList list = XmlUtils.toBean(FriendsList.class, is); - return list; - } - - @Override - protected FriendsList readList(Serializable seri) { - return ((FriendsList) seri); - } - - @Override - protected boolean compareTo(List data, Entity enity) { - int s = data.size(); - if (enity != null) { - for (int i = 0; i < s; i++) { - if (((Friend) enity).getUserid() == ((Friend) data.get(i)) - .getUserid()) { - return true; - } - } - } - return false; - } - - @Override - protected void sendRequestData() { - OSChinaApi.getFriendList(mUid, mCatalog, mCurrentPage, mHandler); - } - - @Override - protected void onRefreshNetworkSuccess() { - if ((NoticeViewPagerFragment.sCurrentPage == 3 || NoticeViewPagerFragment.sShowCount[3] > 0) - && mCatalog == FriendsList.TYPE_FANS - && mUid == AppContext.getInstance().getLoginUid()) { - NoticeUtils.clearNotice(Notice.TYPE_NEWFAN); - UIHelper.sendBroadcastForNotice(getActivity()); - } - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, - long id) { - Friend item = (Friend) mAdapter.getItem(position); - if (item != null) { - if (mUid == AppContext.getInstance().getLoginUid()) { - UIHelper.showMessageDetail(getActivity(), item.getUserid(), - item.getName()); - return; - } - UIHelper.showUserCenter(getActivity(), item.getUserid(), - item.getName()); - } - } -} diff --git a/app/src/main/java/net/oschina/app/fragment/MessageDetailFragment.java b/app/src/main/java/net/oschina/app/fragment/MessageDetailFragment.java deleted file mode 100644 index 15c195191915811ad546ef70b4ee793347c24fec..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/fragment/MessageDetailFragment.java +++ /dev/null @@ -1,461 +0,0 @@ -package net.oschina.app.fragment; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.IntentFilter; -import android.graphics.Color; -import android.os.Bundle; -import android.text.Editable; -import android.util.SparseArray; -import android.view.View; -import android.view.WindowManager; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemLongClickListener; - -import com.loopj.android.http.AsyncHttpResponseHandler; - -import net.oschina.app.AppContext; -import net.oschina.app.R; -import net.oschina.app.adapter.MessageDetailAdapter; -import net.oschina.app.api.OperationResponseHandler; -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.base.BaseActivity; -import net.oschina.app.base.BaseListFragment; -import net.oschina.app.base.ListBaseAdapter; -import net.oschina.app.bean.Comment; -import net.oschina.app.bean.CommentList; -import net.oschina.app.bean.Constants; -import net.oschina.app.bean.MessageDetail; -import net.oschina.app.bean.MessageDetailList; -import net.oschina.app.bean.Result; -import net.oschina.app.bean.ResultBean; -import net.oschina.app.bean.User; -import net.oschina.app.emoji.KJEmojiFragment; -import net.oschina.app.emoji.OnSendClickListener; -import net.oschina.app.ui.empty.EmptyLayout; -import net.oschina.app.util.DialogHelp; -import net.oschina.app.util.HTMLUtil; -import net.oschina.app.util.TDevice; -import net.oschina.app.util.UIHelper; -import net.oschina.app.util.XmlUtils; - -import cz.msebera.android.httpclient.Header; -import org.kymjs.kjframe.utils.StringUtils; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -/** - * 与某人的聊天记录界面(私信详情) - * - * @author kymjs (http://www.kymjs.com/) - * - */ -public class MessageDetailFragment extends BaseListFragment implements - OnItemLongClickListener, OnSendClickListener,MessageDetailAdapter.OnRetrySendMessageListener{ - protected static final String TAG = ActiveFragment.class.getSimpleName(); - public static final String BUNDLE_KEY_FID = "BUNDLE_KEY_FID"; - public static final String BUNDLE_KEY_FNAME = "BUNDLE_KEY_FNAME"; - private static final String CACHE_KEY_PREFIX = "message_detail_list"; - //时间间隔(要求:聊天时间显示,时间间隔为五分钟以上才显示出来) - private final static long TIME_INTERVAL = 1000 * 60 * 5; - - private int mFid; - private String mFName; - private int mMsgTag; - private int mPageCount; - private long mLastShowDate; //最后显示出来的时间 - public KJEmojiFragment emojiFragment = new KJEmojiFragment(); - //存放正在发送的消息,key 为生成的一个临时messageID(msgTag),value为Message实体 - //当消息发送成功后,从mSendingMsgs删除对应的Message实体 - private SparseArray mSendingMsgs = new SparseArray(); - - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (mErrorLayout != null) { - mErrorLayout.setErrorType(EmptyLayout.NETWORK_ERROR); - mErrorLayout.setErrorMessage(getString(R.string.unlogin_tip)); - } - } - }; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - Bundle args = getArguments(); - if (args != null) { - mFid = args.getInt(BUNDLE_KEY_FID); - mFName = args.getString(BUNDLE_KEY_FNAME); - mCatalog = CommentList.CATALOG_MESSAGE; - } - IntentFilter filter = new IntentFilter(Constants.INTENT_ACTION_LOGOUT); - getActivity().registerReceiver(mReceiver, filter); - - ((BaseActivity) getActivity()).setActionBarTitle(mFName); - - int mode = WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN - | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; - getActivity().getWindow().setSoftInputMode(mode); - - getActivity().getSupportFragmentManager().beginTransaction() - .replace(R.id.emoji_container, emojiFragment).commit(); - } - - @Override - public void onDestroy() { - getActivity().unregisterReceiver(mReceiver); - super.onDestroy(); - } - - @Override - public boolean onBackPressed() { - if (emojiFragment.isShowEmojiKeyBoard()) { - emojiFragment.hideAllKeyBoard(); - return true; - } else { - return super.onBackPressed(); - } - } - - @Override - protected MessageDetailAdapter getListAdapter() { - MessageDetailAdapter adapter = new MessageDetailAdapter(); - adapter.setOnRetrySendMessageListener(this); - return adapter; - } - - @Override - protected String getCacheKeyPrefix() { - return CACHE_KEY_PREFIX + mFid; - } - - @Override - protected MessageDetailList parseList(InputStream is) throws Exception { - MessageDetailList list = XmlUtils.toBean(MessageDetailList.class, is); - handleShowDate(list.getList()); - mPageCount = (int) Math.ceil((float) list.getMessageCount() / getPageSize()); - return list; - } - - @Override - protected MessageDetailList readList(Serializable seri) { - MessageDetailList list = ((MessageDetailList) seri); - handleShowDate(list.getList()); - return list; - } - - /** - * 处理时间显示,设置哪些需要显示时间,哪些不需要显示时间 - * @param list - */ - private void handleShowDate(List list) { - MessageDetail msg = null; - long lastGroupTime = 0l; - //因为获得的列表是按时间降序的,所以需要倒着遍历 - for (int i = list.size() - 1; i >= 0; i--) { - msg = list.get(i); - Date date = net.oschina.app.util.StringUtils.toDate(msg.getPubDate()); - if (date != null && isNeedShowDate(date.getTime(), lastGroupTime)) { - lastGroupTime = date.getTime(); - msg.setShowDate(true); - } - } - //只设置最新的时间 - if (lastGroupTime > mLastShowDate) { - mLastShowDate = lastGroupTime; - } - } - - private boolean isNeedShowDate(long currentTime,long lastTime){ - return currentTime - lastTime > TIME_INTERVAL; - } - - @Override - public void initView(View view) { - super.initView(view); - mListView.setDivider(null); - mListView.setDividerHeight(0); - if(!AppContext.getNightModeSwitch()) { - mListView.setBackgroundColor(Color.parseColor("#ebebeb")); - } - mListView.setOnItemLongClickListener(this); - //移除父类设置的OnScrollListener,这里不需要下拉加载 - mListView.setOnScrollListener(null); - mErrorLayout.setOnLayoutClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (AppContext.getInstance().isLogin()) { - requestData(false); - } else { - UIHelper.showLoginActivity(getActivity()); - } - } - }); - } - - @Override - protected void requestData(boolean refresh) { - mErrorLayout.setErrorMessage(""); - if (AppContext.getInstance().isLogin()) { - super.requestData(refresh); - } else { - mErrorLayout.setErrorType(EmptyLayout.NETWORK_ERROR); - mErrorLayout.setErrorMessage(getString(R.string.unlogin_tip)); - } - } - - @Override - protected void sendRequestData() { - OSChinaApi.getChatMessageList(mFid, mCurrentPage, mHandler); - } - - @Override - protected boolean isReadCacheData(boolean refresh) { - if (!TDevice.hasInternet()) { - return true; - } else { - return false; - } - } - - @Override - protected void executeOnLoadDataSuccess(List data) { - mErrorLayout.setErrorType(EmptyLayout.HIDE_LAYOUT); - if (data == null) { - data = new ArrayList(1); - } - if (mAdapter != null) { - if (mCurrentPage == 0) - mAdapter.clear(); - mAdapter.addData(data); - if (data.size() == 0 && mState == STATE_REFRESH) { - mErrorLayout.setErrorType(EmptyLayout.NODATA); - } else if (data.size() < getPageSize()) { - mAdapter.setState(ListBaseAdapter.STATE_OTHER); - } else { - mAdapter.setState(ListBaseAdapter.STATE_LOAD_MORE); - } - mAdapter.notifyDataSetChanged(); - //只有第一次加载,才需要滚动到底部 - if (mCurrentPage == 0) - mListView.setSelection(mListView.getBottom()); - else if (data.size() > 1) { - mListView.setSelection(data.size() - 1); - } - } - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, - long id) {} - - @Override - public boolean onItemLongClick(AdapterView parent, View view, - int position, long id) { - final MessageDetail message = mAdapter.getItem(position); - DialogHelp.getSelectDialog(getActivity(), getResources().getStringArray(R.array.message_list_options), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - switch (i) { - case 0: - TDevice.copyTextToBoard(HTMLUtil.delHTMLTag(message - .getContent())); - break; - case 1: - handleDeleteMessage(message); - break; - default: - break; - } - } - }).show(); - return true; - } - - // 下拉加载数据 - @Override - public void onRefresh() { - if (mState == STATE_REFRESH) { - return; - } - if(mCurrentPage==mPageCount-1){ - AppContext.showToastShort("已加载全部数据!"); - setSwipeRefreshLoadedState(); - return; - } - // 设置顶部正在刷新 - mListView.setSelection(0); - setSwipeRefreshLoadingState(); - mState = STATE_REFRESH; - mCurrentPage++; - requestData(true); - } - - public void showFriendUserCenter(){ - UIHelper.showUserCenter(getActivity(), mFid, mFName); - } - - @Override - public void onResume() { - super.onResume(); - emojiFragment.hideFlagButton(); - } - - private void handleDeleteMessage(final MessageDetail message) { - DialogHelp.getConfirmDialog(getActivity(), "是否删除该私信?", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - showWaitDialog(R.string.progress_submit); - OSChinaApi.deleteComment(mFid, - CommentList.CATALOG_MESSAGE, message.getId(), - message.getAuthorId(), - new DeleteMessageOperationHandler(message)); - } - }).show(); - } - - class DeleteMessageOperationHandler extends OperationResponseHandler { - - public DeleteMessageOperationHandler(Object... args) { - super(args); - } - - @Override - public void onSuccess(int code, ByteArrayInputStream is, Object[] args) - throws Exception { - Result res = XmlUtils.toBean(ResultBean.class, is).getResult(); - if (res.OK()) { - Comment msg = (Comment) args[0]; - mAdapter.removeItem(msg); - mAdapter.notifyDataSetChanged(); - hideWaitDialog(); - AppContext.showToastShort(R.string.tip_delete_success); - } else { - AppContext.showToastShort(res.getErrorMessage()); - hideWaitDialog(); - } - } - - @Override - public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { - - } - - @Override - public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { - AppContext.showToastShort(R.string.tip_delete_faile); - hideWaitDialog(); - } - } - - @Override - public void onClickSendButton(Editable str) { - if (!AppContext.getInstance().isLogin()) { - UIHelper.showLoginActivity(getActivity()); - return; - } - if (StringUtils.isEmpty(str)) { - AppContext.showToastShort(R.string.tip_content_empty); - return; - } - MessageDetail message = new MessageDetail(); - User user = AppContext.getInstance().getLoginUser(); - int msgTag = mMsgTag++; - message.setId(msgTag); - message.setPortrait(user.getPortrait()); - message.setAuthor(user.getName()); - message.setAuthorId(user.getId()); - message.setContent(str.toString()); - sendMessage(message); - } - - /** - * 发送消息 - * @param msg - */ - private void sendMessage(MessageDetail msg){ - msg.setStatus(MessageDetail.MessageStatus.SENDING); - Date date = new Date(); - msg.setPubDate(net.oschina.app.util.StringUtils.getDateString(date)); - //如果此次发表的时间距离上次的时间达到了 TIME_INTERVAL 的间隔要求,则显示时间 - if(isNeedShowDate(date.getTime(),mLastShowDate)) { - msg.setShowDate(true); - mLastShowDate = date.getTime(); - } - - //如果待发送列表没有此条消息,说明是新消息,不是发送失败再次发送的,不需要再次添加 - if(mSendingMsgs.indexOfKey(msg.getId())<0) { - mSendingMsgs.put(msg.getId(), msg); - mAdapter.addItem(0, msg); - mListView.setSelection(mListView.getBottom()); - }else{ - mAdapter.notifyDataSetChanged(); - } - OSChinaApi.publicMessage(msg.getAuthorId(), mFid, msg.getContent(), new SendMessageResponseHandler(msg.getId())); - } - - @Override - public void onClickFlagButton() {} - - @Override - public void onRetrySendMessage(int msgId) { - MessageDetail message = mSendingMsgs.get(msgId); - if (message != null) { - sendMessage(message); - } - } - - class SendMessageResponseHandler extends AsyncHttpResponseHandler{ - - private int msgTag; - - public SendMessageResponseHandler(int msgTag) { - this.msgTag = msgTag; - } - - @Override - public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { - try { - ResultBean resb = XmlUtils.toBean(ResultBean.class, - new ByteArrayInputStream(arg2)); - Result res = resb.getResult(); - if (res.OK()) { - //从mSendingMsgs获取发送时放入的MessageDetail实体 - MessageDetail message = mSendingMsgs.get(this.msgTag); - MessageDetail serverMsg = resb.getMessage(); - //把id设置为服务器返回的id - message.setId(serverMsg.getId()); - message.setStatus(MessageDetail.MessageStatus.NORMAL); - //从待发送列表移除 - mSendingMsgs.remove(this.msgTag); - mAdapter.notifyDataSetChanged(); - } else { - error(); - AppContext.showToastShort(res.getErrorMessage()); - } - emojiFragment.clean(); - } catch (Exception e) { - e.printStackTrace(); - onFailure(arg0, arg1, arg2, e); - } - } - - - @Override - public void onFailure(int arg0, Header[] arg1, byte[] arg2, Throwable arg3) { - error(); - } - - private void error(){ - mSendingMsgs.get(this.msgTag).setStatus(MessageDetail.MessageStatus.ERROR); - mAdapter.notifyDataSetChanged(); - } - } -} diff --git a/app/src/main/java/net/oschina/app/fragment/MessageFragment.java b/app/src/main/java/net/oschina/app/fragment/MessageFragment.java deleted file mode 100644 index 39d45505ccff4cd86b053dcfae267314107b4c52..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/fragment/MessageFragment.java +++ /dev/null @@ -1,239 +0,0 @@ -package net.oschina.app.fragment; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Bundle; -import android.view.View; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemLongClickListener; -import cz.msebera.android.httpclient.Header; - -import net.oschina.app.AppContext; -import net.oschina.app.R; -import net.oschina.app.adapter.MessageAdapter; -import net.oschina.app.api.OperationResponseHandler; -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.base.BaseListFragment; -import net.oschina.app.bean.Constants; -import net.oschina.app.bean.MessageList; -import net.oschina.app.bean.Messages; -import net.oschina.app.bean.Notice; -import net.oschina.app.bean.Result; -import net.oschina.app.bean.ResultBean; -import net.oschina.app.service.NoticeUtils; -import net.oschina.app.ui.MainActivity; -import net.oschina.app.ui.empty.EmptyLayout; -import net.oschina.app.util.DialogHelp; -import net.oschina.app.util.HTMLUtil; -import net.oschina.app.util.TDevice; -import net.oschina.app.util.UIHelper; -import net.oschina.app.util.XmlUtils; -import net.oschina.app.viewpagerfragment.NoticeViewPagerFragment; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.io.Serializable; - -public class MessageFragment extends BaseListFragment implements - OnItemLongClickListener { - protected static final String TAG = ActiveFragment.class.getSimpleName(); - private static final String CACHE_KEY_PREFIX = "message_list"; - private boolean mIsWatingLogin; - - private final BroadcastReceiver mLogoutReceiver = new BroadcastReceiver() { - - @Override - public void onReceive(Context context, Intent intent) { - if (mErrorLayout != null) { - mIsWatingLogin = true; - mErrorLayout.setErrorType(EmptyLayout.NETWORK_ERROR); - mErrorLayout.setErrorMessage(getString(R.string.unlogin_tip)); - } - } - }; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - IntentFilter filter = new IntentFilter(Constants.INTENT_ACTION_LOGOUT); - getActivity().registerReceiver(mLogoutReceiver, filter); - } - - @Override - public void onDestroy() { - getActivity().unregisterReceiver(mLogoutReceiver); - super.onDestroy(); - } - - @Override - public void onResume() { - if (mIsWatingLogin) { - mCurrentPage = 0; - mState = STATE_REFRESH; - requestData(false); - } - refreshNotice(); - super.onResume(); - } - - private void refreshNotice() { - Notice notice = MainActivity.mNotice; - if (notice != null && notice.getMsgCount() > 0) { - onRefresh(); - } - } - - @Override - protected MessageAdapter getListAdapter() { - return new MessageAdapter(); - } - - @Override - protected String getCacheKeyPrefix() { - return CACHE_KEY_PREFIX; - } - - @Override - protected MessageList parseList(InputStream is) throws Exception { - MessageList list = XmlUtils.toBean(MessageList.class, is); - return list; - } - - @Override - protected MessageList readList(Serializable seri) { - return ((MessageList) seri); - } - - @Override - public void initView(View view) { - super.initView(view); - mListView.setDivider(null); - mListView.setDividerHeight(0); - mListView.setOnItemLongClickListener(this); - mErrorLayout.setOnLayoutClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (AppContext.getInstance().isLogin()) { - mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING); - requestData(false); - } else { - UIHelper.showLoginActivity(getActivity()); - } - } - }); - if (AppContext.getInstance().isLogin()) { - UIHelper.sendBroadcastForNotice(getActivity()); - } - } - - @Override - protected void requestData(boolean refresh) { - if (AppContext.getInstance().isLogin()) { - mIsWatingLogin = false; - super.requestData(refresh); - } else { - mIsWatingLogin = true; - mErrorLayout.setErrorType(EmptyLayout.NETWORK_ERROR); - mErrorLayout.setErrorMessage(getString(R.string.unlogin_tip)); - } - } - - @Override - protected void sendRequestData() { - OSChinaApi.getMessageList(AppContext.getInstance().getLoginUid(), - mCurrentPage, mHandler); - } - - @Override - protected void onRefreshNetworkSuccess() { - if (2 == NoticeViewPagerFragment.sCurrentPage - || NoticeViewPagerFragment.sShowCount[2] > 0) { // 在page中第三个位置 - NoticeUtils.clearNotice(Notice.TYPE_MESSAGE); - UIHelper.sendBroadcastForNotice(getActivity()); - } - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, - long id) { - Messages message = (Messages) mAdapter.getItem(position); - if (message != null) - UIHelper.showMessageDetail(getActivity(), message.getFriendId(), - message.getFriendName()); - } - - @Override - public boolean onItemLongClick(AdapterView parent, View view, - int position, long id) { - final Messages message = (Messages) mAdapter.getItem(position); - DialogHelp.getSelectDialog(getActivity(), getResources().getStringArray(R.array.message_list_options), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - switch (i) { - case 0: - TDevice.copyTextToBoard(HTMLUtil.delHTMLTag(message - .getContent())); - break; - case 1: - handleDeleteMessage(message); - break; - default: - break; - } - } - }).show(); - return true; - } - - private void handleDeleteMessage(final Messages message) { - - DialogHelp.getConfirmDialog(getActivity(), getString(R.string.confirm_delete_message, - message.getFriendName()), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - showWaitDialog(R.string.progress_submit); - - OSChinaApi.deleteMessage(AppContext.getInstance() - .getLoginUid(), message.getFriendId(), - new DeleteMessageOperationHandler(message)); - } - }).show(); - } - - class DeleteMessageOperationHandler extends OperationResponseHandler { - - public DeleteMessageOperationHandler(Object... args) { - super(args); - } - - @Override - public void onSuccess(int code, ByteArrayInputStream is, Object[] args) - throws Exception { - Result res = XmlUtils.toBean(ResultBean.class, is).getResult(); - if (res.OK()) { - Messages msg = (Messages) args[0]; - mAdapter.removeItem(msg); - mAdapter.notifyDataSetChanged(); - hideWaitDialog(); - AppContext.showToastShort(R.string.tip_delete_success); - } else { - AppContext.showToastShort(res.getErrorMessage()); - hideWaitDialog(); - } - } - - @Override - public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { - - } - - @Override - public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { - AppContext.showToastShort(R.string.tip_delete_faile); - hideWaitDialog(); - } - } -} diff --git a/app/src/main/java/net/oschina/app/fragment/MyInformationFragment.java b/app/src/main/java/net/oschina/app/fragment/MyInformationFragment.java deleted file mode 100644 index b2f295f95cdcf268a955c86de54157d74daf93f9..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/fragment/MyInformationFragment.java +++ /dev/null @@ -1,421 +0,0 @@ -package net.oschina.app.fragment; - -import java.io.ByteArrayInputStream; -import java.io.Serializable; -import java.lang.ref.WeakReference; - -import net.oschina.app.AppContext; -import net.oschina.app.R; -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.base.BaseFragment; -import net.oschina.app.bean.Constants; -import net.oschina.app.bean.MyInformation; -import net.oschina.app.bean.Notice; -import net.oschina.app.bean.SimpleBackPage; -import net.oschina.app.bean.User; -import net.oschina.app.cache.CacheManager; -import net.oschina.app.ui.MainActivity; -import net.oschina.app.ui.MyQrodeDialog; -import net.oschina.app.ui.empty.EmptyLayout; -import net.oschina.app.util.StringUtils; -import net.oschina.app.util.TDevice; -import net.oschina.app.util.UIHelper; -import net.oschina.app.util.XmlUtils; -import net.oschina.app.widget.AvatarView; -import net.oschina.app.widget.BadgeView; - - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.AsyncTask; -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.util.TypedValue; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; -import butterknife.ButterKnife; -import butterknife.InjectView; -import cz.msebera.android.httpclient.Header; - -import com.loopj.android.http.AsyncHttpResponseHandler; - -/** - * 登录用户中心页面 - * - * @author FireAnt(http://my.oschina.net/LittleDY) - * @author kymjs (http://my.oschina.net/kymjs) - * @version 创建时间:2014年10月30日 下午4:05:47 - */ -public class MyInformationFragment extends BaseFragment { - - public static final int sChildView = 9; // 在没有加入TeamList控件时rootview有多少子布局 - - @InjectView(R.id.iv_avatar) - AvatarView mIvAvatar; - @InjectView(R.id.iv_gender) - ImageView mIvGender; - @InjectView(R.id.tv_name) - TextView mTvName; - @InjectView(R.id.tv_score) - TextView mTvScore; - @InjectView(R.id.tv_favorite) - TextView mTvFavorite; - @InjectView(R.id.tv_following) - TextView mTvFollowing; - @InjectView(R.id.tv_follower) - TextView mTvFans; - @InjectView(R.id.tv_mes) - View mMesView; - @InjectView(R.id.error_layout) - EmptyLayout mErrorLayout; - @InjectView(R.id.iv_qr_code) - ImageView mQrCode; - @InjectView(R.id.ll_user_container) - View mUserContainer; - @InjectView(R.id.rl_user_unlogin) - View mUserUnLogin; - @InjectView(R.id.rootview) - LinearLayout rootView; - - private static BadgeView mMesCount; - - private boolean mIsWatingLogin; - - private User mInfo; - private AsyncTask mCacheTask; - - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { - - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (action.equals(Constants.INTENT_ACTION_LOGOUT)) { - if (mErrorLayout != null) { - mIsWatingLogin = true; - steupUser(); - mMesCount.hide(); - } - } else if (action.equals(Constants.INTENT_ACTION_USER_CHANGE)) { - requestData(true); - } else if (action.equals(Constants.INTENT_ACTION_NOTICE)) { - setNotice(); - } - } - }; - - private final AsyncHttpResponseHandler mHandler = new AsyncHttpResponseHandler() { - @Override - public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { - try { - mInfo = XmlUtils.toBean(MyInformation.class, - new ByteArrayInputStream(arg2)).getUser(); - if (mInfo != null) { - fillUI(); - AppContext.getInstance().updateUserInfo(mInfo); - new SaveCacheTask(getActivity(), mInfo, getCacheKey()) - .execute(); - } else { - onFailure(arg0, arg1, arg2, new Throwable()); - } - } catch (Exception e) { - e.printStackTrace(); - onFailure(arg0, arg1, arg2, e); - } - } - - @Override - public void onFailure(int arg0, Header[] arg1, byte[] arg2, - Throwable arg3) {} - }; - - private void steupUser() { - if (mIsWatingLogin) { - mUserContainer.setVisibility(View.GONE); - mUserUnLogin.setVisibility(View.VISIBLE); - } else { - mUserContainer.setVisibility(View.VISIBLE); - mUserUnLogin.setVisibility(View.GONE); - } - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - IntentFilter filter = new IntentFilter(Constants.INTENT_ACTION_LOGOUT); - filter.addAction(Constants.INTENT_ACTION_USER_CHANGE); - getActivity().registerReceiver(mReceiver, filter); - } - - @Override - public void onResume() { - super.onResume(); - setNotice(); - } - - public void setNotice() { - if (MainActivity.mNotice != null) { - - Notice notice = MainActivity.mNotice; - int atmeCount = notice.getAtmeCount();// @我 - int msgCount = notice.getMsgCount();// 留言 - int reviewCount = notice.getReviewCount();// 评论 - int newFansCount = notice.getNewFansCount();// 新粉丝 - int newLikeCount = notice.getNewLikeCount();// 获得点赞 - int activeCount = atmeCount + reviewCount + msgCount + newFansCount + newLikeCount;// 信息总数 - if (activeCount > 0) { - mMesCount.setText(activeCount + ""); - mMesCount.show(); - } else { - mMesCount.hide(); - } - - } else { - mMesCount.hide(); - } - } - - @Override - public void onDestroy() { - super.onDestroy(); - getActivity().unregisterReceiver(mReceiver); - } - - @Override - public View onCreateView(LayoutInflater inflater, - @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_my_information, - container, false); - ButterKnife.inject(this, view); - initView(view); - return view; - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - requestData(true); - mInfo = AppContext.getInstance().getLoginUser(); - fillUI(); - } - - @Override - public void initView(View view) { - mErrorLayout.setErrorType(EmptyLayout.HIDE_LAYOUT); - mIvAvatar.setOnClickListener(this); - mErrorLayout.setOnLayoutClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (AppContext.getInstance().isLogin()) { - requestData(true); - } else { - UIHelper.showLoginActivity(getActivity()); - } - } - }); - view.findViewById(R.id.ly_favorite).setOnClickListener(this); - view.findViewById(R.id.ly_following).setOnClickListener(this); - view.findViewById(R.id.ly_follower).setOnClickListener(this); - view.findViewById(R.id.rl_message).setOnClickListener(this); - view.findViewById(R.id.rl_team).setOnClickListener(this); - view.findViewById(R.id.rl_blog).setOnClickListener(this); - view.findViewById(R.id.rl_note).setOnClickListener( - new OnClickListener() { - @Override - public void onClick(View v) { - UIHelper.showSimpleBack(getActivity(), - SimpleBackPage.NOTE); - } - }); - mUserUnLogin.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - UIHelper.showLoginActivity(getActivity()); - } - }); - - mMesCount = new BadgeView(getActivity(), mMesView); - mMesCount.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10); - mMesCount.setBadgePosition(BadgeView.POSITION_CENTER); - mMesCount.setGravity(Gravity.CENTER); - mMesCount.setBackgroundResource(R.drawable.notification_bg); - mQrCode.setOnClickListener(this); - // // 初始化团队列表数据 - // String cache = PreferenceHelper.readString(getActivity(), - // TEAM_LIST_FILE, TEAM_LIST_KEY); - // if (!StringUtils.isEmpty(cache)) { - // List teams = TeamList.toTeamList(cache); - // addTeamLayout(teams); - // } - } - - private void fillUI() { - if (mInfo == null) - return; - mIvAvatar.setAvatarUrl(mInfo.getPortrait()); - mTvName.setText(mInfo.getName()); - mIvGender - .setImageResource(StringUtils.toInt(mInfo.getGender()) != 2 ? R.drawable.userinfo_icon_male - : R.drawable.userinfo_icon_female); - mTvScore.setText(String.valueOf(mInfo.getScore())); - mTvFavorite.setText(String.valueOf(mInfo.getFavoritecount())); - mTvFollowing.setText(String.valueOf(mInfo.getFollowers())); - mTvFans.setText(String.valueOf(mInfo.getFans())); - } - - private void requestData(boolean refresh) { - if (AppContext.getInstance().isLogin()) { - mIsWatingLogin = false; - String key = getCacheKey(); - if (refresh || TDevice.hasInternet() - && (!CacheManager.isExistDataCache(getActivity(), key))) { - sendRequestData(); - } else { - readCacheData(key); - } - } else { - mIsWatingLogin = true; - } - steupUser(); - } - - private void readCacheData(String key) { - cancelReadCacheTask(); - mCacheTask = new CacheTask(getActivity()).execute(key); - } - - private void cancelReadCacheTask() { - if (mCacheTask != null) { - mCacheTask.cancel(true); - mCacheTask = null; - } - } - - private void sendRequestData() { - int uid = AppContext.getInstance().getLoginUid(); - OSChinaApi.getMyInformation(uid, mHandler); - } - - private String getCacheKey() { - return "my_information" + AppContext.getInstance().getLoginUid(); - } - - private class CacheTask extends AsyncTask { - private final WeakReference mContext; - - private CacheTask(Context context) { - mContext = new WeakReference(context); - } - - @Override - protected User doInBackground(String... params) { - Serializable seri = CacheManager.readObject(mContext.get(), - params[0]); - if (seri == null) { - return null; - } else { - return (User) seri; - } - } - - @Override - protected void onPostExecute(User info) { - super.onPostExecute(info); - if (info != null) { - mInfo = info; - // mErrorLayout.setErrorType(EmptyLayout.HIDE_LAYOUT); - // } else { - // mErrorLayout.setErrorType(EmptyLayout.NETWORK_ERROR); - fillUI(); - } - } - } - - private class SaveCacheTask extends AsyncTask { - private final WeakReference mContext; - private final Serializable seri; - private final String key; - - private SaveCacheTask(Context context, Serializable seri, String key) { - mContext = new WeakReference(context); - this.seri = seri; - this.key = key; - } - - @Override - protected Void doInBackground(Void... params) { - CacheManager.saveObject(mContext.get(), seri, key); - return null; - } - } - - @Override - public void onClick(View v) { - if (mIsWatingLogin) { - AppContext.showToast(R.string.unlogin); - UIHelper.showLoginActivity(getActivity()); - return; - } - final int id = v.getId(); - switch (id) { - case R.id.iv_avatar: - UIHelper.showSimpleBack(getActivity(), - SimpleBackPage.MY_INFORMATION_DETAIL); - break; - case R.id.iv_qr_code: - showMyQrCode(); - break; - case R.id.ly_following: - UIHelper.showFriends(getActivity(), AppContext.getInstance() - .getLoginUid(), 0); - break; - case R.id.ly_follower: - UIHelper.showFriends(getActivity(), AppContext.getInstance() - .getLoginUid(), 1); - break; - case R.id.ly_favorite: - UIHelper.showUserFavorite(getActivity(), AppContext.getInstance() - .getLoginUid()); - break; - case R.id.rl_message: - UIHelper.showMyMes(getActivity()); - setNoticeReaded(); - break; - case R.id.rl_team: - UIHelper.showTeamMainActivity(getActivity()); - break; - case R.id.rl_blog: - UIHelper.showUserBlog(getActivity(), AppContext.getInstance() - .getLoginUid()); - break; - case R.id.rl_user_center: - UIHelper.showUserCenter(getActivity(), AppContext.getInstance() - .getLoginUid(), AppContext.getInstance().getLoginUser() - .getName()); - break; - default: - break; - } - } - - private void showMyQrCode() { - MyQrodeDialog dialog = new MyQrodeDialog(getActivity()); - dialog.show(); - } - - @Override - public void initData() {} - - private void setNoticeReaded() { - mMesCount.setText(""); - mMesCount.hide(); - } - -} diff --git a/app/src/main/java/net/oschina/app/fragment/MyInformationFragmentDetail.java b/app/src/main/java/net/oschina/app/fragment/MyInformationFragmentDetail.java index a47663fa47305d33bb23d0c2b27f0b452ba3432b..d5940f9af27d45a885e693e8a8628d8217ab5d18 100644 --- a/app/src/main/java/net/oschina/app/fragment/MyInformationFragmentDetail.java +++ b/app/src/main/java/net/oschina/app/fragment/MyInformationFragmentDetail.java @@ -1,51 +1,22 @@ package net.oschina.app.fragment; -import android.app.Activity; -import android.content.DialogInterface; -import android.content.Intent; -import android.graphics.Bitmap; -import android.net.Uri; -import android.os.Build; import android.os.Bundle; -import android.os.Environment; -import android.provider.MediaStore; -import android.provider.MediaStore.Images; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; -import com.loopj.android.http.AsyncHttpResponseHandler; - -import net.oschina.app.AppContext; import net.oschina.app.R; -import net.oschina.app.api.remote.OSChinaApi; import net.oschina.app.base.BaseFragment; -import net.oschina.app.bean.MyInformation; -import net.oschina.app.bean.Result; -import net.oschina.app.bean.ResultBean; -import net.oschina.app.bean.User; +import net.oschina.app.improve.bean.User; import net.oschina.app.ui.empty.EmptyLayout; -import net.oschina.app.util.DialogHelp; -import net.oschina.app.util.FileUtil; -import net.oschina.app.util.ImageUtils; import net.oschina.app.util.StringUtils; -import net.oschina.app.util.UIHelper; -import net.oschina.app.util.XmlUtils; import org.kymjs.kjframe.Core; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileNotFoundException; -import java.text.SimpleDateFormat; -import java.util.Date; - +import butterknife.Bind; import butterknife.ButterKnife; -import butterknife.InjectView; -import butterknife.OnClick; -import cz.msebera.android.httpclient.Header; /** * 登录用户信息详情 @@ -56,69 +27,35 @@ import cz.msebera.android.httpclient.Header; public class MyInformationFragmentDetail extends BaseFragment { - public static final int ACTION_TYPE_ALBUM = 0; - public static final int ACTION_TYPE_PHOTO = 1; - - @InjectView(R.id.iv_avatar) + @Bind(R.id.iv_avatar) ImageView mUserFace; - @InjectView(R.id.tv_name) + @Bind(R.id.tv_name) TextView mName; - @InjectView(R.id.tv_join_time) + @Bind(R.id.tv_join_time) TextView mJoinTime; - @InjectView(R.id.tv_location) + @Bind(R.id.tv_location) TextView mFrom; - @InjectView(R.id.tv_development_platform) + @Bind(R.id.tv_development_platform) TextView mPlatFrom; - @InjectView(R.id.tv_academic_focus) + @Bind(R.id.tv_academic_focus) TextView mFocus; - @InjectView(R.id.error_layout) + @Bind(R.id.error_layout) EmptyLayout mErrorLayout; - private User mUser; - - private boolean isChangeFace = false; - - private String theLarge; - - private final static int CROP = 200; + private User userInfo; - private final static String FILE_SAVEPATH = Environment - .getExternalStorageDirectory().getAbsolutePath() - + "/OSChina/Portrait/"; - private Uri origUri; - private Uri cropUri; - private File protraitFile; - private Bitmap protraitBitmap; - private String protraitPath; - - private final AsyncHttpResponseHandler mHandler = new AsyncHttpResponseHandler() { - - @Override - public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { - mErrorLayout.setErrorType(EmptyLayout.HIDE_LAYOUT); - MyInformation user = XmlUtils.toBean(MyInformation.class, - new ByteArrayInputStream(arg2)); - if (user != null && user.getUser() != null) { - mUser = user.getUser(); - fillUI(); - } else { - this.onFailure(arg0, arg1, arg2, null); - } - } - - @Override - public void onFailure(int arg0, Header[] arg1, byte[] arg2, - Throwable arg3) { - mErrorLayout.setErrorType(EmptyLayout.NETWORK_ERROR); - } - - }; + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Bundle arguments = getArguments(); + userInfo = (User) arguments.getSerializable("user_info"); + } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, @@ -130,273 +67,26 @@ public class MyInformationFragmentDetail extends BaseFragment { return view; } - @Override - @OnClick({R.id.iv_avatar, R.id.btn_logout}) - public void onClick(View v) { - switch (v.getId()) { - case R.id.iv_avatar: - showClickAvatar(); - break; - case R.id.btn_logout: - AppContext.getInstance().Logout(); - AppContext.showToastShort(R.string.tip_logout_success); - getActivity().finish(); - break; - default: - break; - } - } - - public void showClickAvatar() { - if (mUser == null) { - AppContext.showToast(""); - return; - } - DialogHelp.getSelectDialog(getActivity(), "选择操作", getResources().getStringArray(R.array.avatar_option), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (i == 0) { - handleSelectPicture(); - } else { - UIHelper.showUserAvatar(getActivity(), - mUser.getPortrait()); - } - } - }).show(); - } - - private void handleSelectPicture() { - DialogHelp.getSelectDialog(getActivity(), "选择图片", getResources().getStringArray(R.array.choose_picture), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - goToSelectPicture(i); - } - }).show(); - } - - private void goToSelectPicture(int position) { - switch (position) { - case ACTION_TYPE_ALBUM: - startImagePick(); - break; - case ACTION_TYPE_PHOTO: - startTakePhoto(); - break; - default: - break; - } - } - @Override public void initView(View view) { - ButterKnife.inject(this, view); - mErrorLayout.setOnLayoutClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - sendRequiredData(); - } - }); - - mUserFace.setOnClickListener(this); + ButterKnife.bind(this, view); } @Override public void initData() { - sendRequiredData(); + // sendRequiredData(); + fillUI(); } + @SuppressWarnings("deprecation") public void fillUI() { - Core.getKJBitmap().displayWithLoadBitmap(mUserFace, mUser.getPortrait(), - R.drawable.widget_dface); - mName.setText(mUser.getName()); - mJoinTime.setText(StringUtils.friendly_time(mUser.getJointime())); - mFrom.setText(mUser.getFrom()); - mPlatFrom.setText(mUser.getDevplatform()); - mFocus.setText(mUser.getExpertise()); - } - - public void sendRequiredData() { - mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING); - OSChinaApi.getMyInformation(AppContext.getInstance().getLoginUid(), - mHandler); + Core.getKJBitmap().displayWithLoadBitmap(mUserFace, userInfo.getPortrait(), + R.mipmap.widget_dface); + mName.setText(userInfo.getName()); + mJoinTime.setText(StringUtils.formatYearMonthDayNew(userInfo.getMore().getJoinDate())); + mFrom.setText(userInfo.getMore().getCity()); + mPlatFrom.setText(userInfo.getMore().getPlatform()); + mFocus.setText(userInfo.getMore().getExpertise()); } - /** - * 上传新照片 - */ - private void uploadNewPhoto() { - showWaitDialog("正在上传头像..."); - - // 获取头像缩略图 - if (!StringUtils.isEmpty(protraitPath) && protraitFile.exists()) { - protraitBitmap = ImageUtils - .loadImgThumbnail(protraitPath, 200, 200); - } else { - AppContext.showToast("图像不存在,上传失败"); - } - if (protraitBitmap != null) { - - try { - OSChinaApi.updatePortrait(AppContext.getInstance() - .getLoginUid(), protraitFile, - new AsyncHttpResponseHandler() { - - @Override - public void onSuccess(int arg0, Header[] arg1, - byte[] arg2) { - Result res = XmlUtils.toBean(ResultBean.class, - new ByteArrayInputStream(arg2)) - .getResult(); - if (res.OK()) { - AppContext.showToast("更换成功"); - // 显示新头像 - mUserFace.setImageBitmap(protraitBitmap); - isChangeFace = true; - } else { - AppContext.showToast(res.getErrorMessage()); - } - } - - @Override - public void onFailure(int arg0, Header[] arg1, - byte[] arg2, Throwable arg3) { - AppContext.showToast("更换头像失败"); - } - - @Override - public void onFinish() { - hideWaitDialog(); - } - }); - } catch (FileNotFoundException e) { - AppContext.showToast("图像不存在,上传失败"); - } - } - } - - /** - * 选择图片裁剪 - */ - private void startImagePick() { - Intent intent; - if (Build.VERSION.SDK_INT < 19) { - intent = new Intent(); - intent.setAction(Intent.ACTION_GET_CONTENT); - intent.setType("image/*"); - startActivityForResult(Intent.createChooser(intent, "选择图片"), - ImageUtils.REQUEST_CODE_GETIMAGE_BYCROP); - } else { - intent = new Intent(Intent.ACTION_PICK, - Images.Media.EXTERNAL_CONTENT_URI); - intent.setType("image/*"); - startActivityForResult(Intent.createChooser(intent, "选择图片"), - ImageUtils.REQUEST_CODE_GETIMAGE_BYCROP); - } - } - - private void startTakePhoto() { - Intent intent; - // 判断是否挂载了SD卡 - String savePath = ""; - String storageState = Environment.getExternalStorageState(); - if (storageState.equals(Environment.MEDIA_MOUNTED)) { - savePath = Environment.getExternalStorageDirectory() - .getAbsolutePath() + "/oschina/Camera/"; - File savedir = new File(savePath); - if (!savedir.exists()) { - savedir.mkdirs(); - } - } - - // 没有挂载SD卡,无法保存文件 - if (StringUtils.isEmpty(savePath)) { - AppContext.showToastShort("无法保存照片,请检查SD卡是否挂载"); - return; - } - - String timeStamp = new SimpleDateFormat("yyyyMMddHHmmss") - .format(new Date()); - String fileName = "osc_" + timeStamp + ".jpg";// 照片命名 - File out = new File(savePath, fileName); - Uri uri = Uri.fromFile(out); - origUri = uri; - - theLarge = savePath + fileName;// 该照片的绝对路径 - - intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); - intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); - startActivityForResult(intent, - ImageUtils.REQUEST_CODE_GETIMAGE_BYCAMERA); - } - - // 裁剪头像的绝对路径 - private Uri getUploadTempFile(Uri uri) { - String storageState = Environment.getExternalStorageState(); - if (storageState.equals(Environment.MEDIA_MOUNTED)) { - File savedir = new File(FILE_SAVEPATH); - if (!savedir.exists()) { - savedir.mkdirs(); - } - } else { - AppContext.showToast("无法保存上传的头像,请检查SD卡是否挂载"); - return null; - } - String timeStamp = new SimpleDateFormat("yyyyMMddHHmmss") - .format(new Date()); - String thePath = ImageUtils.getAbsolutePathFromNoStandardUri(uri); - - // 如果是标准Uri - if (StringUtils.isEmpty(thePath)) { - thePath = ImageUtils.getAbsoluteImagePath(getActivity(), uri); - } - String ext = FileUtil.getFileFormat(thePath); - ext = StringUtils.isEmpty(ext) ? "jpg" : ext; - // 照片命名 - String cropFileName = "osc_crop_" + timeStamp + "." + ext; - // 裁剪头像的绝对路径 - protraitPath = FILE_SAVEPATH + cropFileName; - protraitFile = new File(protraitPath); - - cropUri = Uri.fromFile(protraitFile); - return this.cropUri; - } - - /** - * 拍照后裁剪 - * - * @param data 原始图片 - */ - private void startActionCrop(Uri data) { - Intent intent = new Intent("com.android.camera.action.CROP"); - intent.setDataAndType(data, "image/*"); - intent.putExtra("output", this.getUploadTempFile(data)); - intent.putExtra("crop", "true"); - intent.putExtra("aspectX", 1);// 裁剪框比例 - intent.putExtra("aspectY", 1); - intent.putExtra("outputX", CROP);// 输出图片大小 - intent.putExtra("outputY", CROP); - intent.putExtra("scale", true);// 去黑边 - intent.putExtra("scaleUpIfNeeded", true);// 去黑边 - startActivityForResult(intent, - ImageUtils.REQUEST_CODE_GETIMAGE_BYSDCARD); - } - - @Override - public void onActivityResult(final int requestCode, final int resultCode, - final Intent imageReturnIntent) { - if (resultCode != Activity.RESULT_OK) - return; - - switch (requestCode) { - case ImageUtils.REQUEST_CODE_GETIMAGE_BYCAMERA: - startActionCrop(origUri);// 拍照后裁剪 - break; - case ImageUtils.REQUEST_CODE_GETIMAGE_BYCROP: - startActionCrop(imageReturnIntent.getData());// 选图后裁剪 - break; - case ImageUtils.REQUEST_CODE_GETIMAGE_BYSDCARD: - uploadNewPhoto(); - break; - } - } } diff --git a/app/src/main/java/net/oschina/app/fragment/NewsDetailFragment.java b/app/src/main/java/net/oschina/app/fragment/NewsDetailFragment.java deleted file mode 100644 index b574db747d519f9d5998c7a25d598a5300dbea1f..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/fragment/NewsDetailFragment.java +++ /dev/null @@ -1,127 +0,0 @@ -package net.oschina.app.fragment; - -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.base.CommonDetailFragment; -import net.oschina.app.bean.CommentList; -import net.oschina.app.bean.FavoriteList; -import net.oschina.app.bean.News; -import net.oschina.app.bean.NewsDetail; -import net.oschina.app.util.StringUtils; -import net.oschina.app.util.ThemeSwitchUtils; -import net.oschina.app.util.UIHelper; -import net.oschina.app.util.XmlUtils; - -import java.io.InputStream; - -/** - * Created by 火蚁 on 15/5/25. - */ -public class NewsDetailFragment extends CommonDetailFragment { - - @Override - protected String getCacheKey() { - return "news_" + mId; - } - - @Override - protected void sendRequestDataForNet() { - OSChinaApi.getNewsDetail(mId, mDetailHeandler); - } - - @Override - protected News parseData(InputStream is) { - return XmlUtils.toBean(NewsDetail.class, is).getNews(); - } - - @Override - protected String getWebViewBody(News detail) { - StringBuffer body = new StringBuffer(); - body.append(UIHelper.WEB_STYLE).append(UIHelper.WEB_LOAD_IMAGES); - body.append(ThemeSwitchUtils.getWebViewBodyString()); - // 添加title - body.append(String.format("
%s
", mDetail.getTitle())); - // 添加作者和时间 - String time = StringUtils.friendly_time(mDetail.getPubDate()); - String author = String.format("%s", mDetail.getAuthorId(), mDetail.getAuthor()); - body.append(String.format("
%s    %s
", author, time)); - // 添加图片点击放大支持 - body.append(UIHelper.setHtmlCotentSupportImagePreview(mDetail.getBody())); - - - // 更多关于***软件的信息 - String softwareName = mDetail.getSoftwareName(); - String softwareLink = mDetail.getSoftwareLink(); - if (!StringUtils.isEmpty(softwareName) - && !StringUtils.isEmpty(softwareLink)) - body.append(String - .format("
更多关于: %s 的详细信息
", - softwareLink, softwareName)); - - // 相关新闻 - if (mDetail != null && mDetail.getRelatives() != null - && mDetail.getRelatives().size() > 0) { - String strRelative = ""; - for (News.Relative relative : mDetail.getRelatives()) { - strRelative += String.format( - "
  • %s
  • ", - relative.url, relative.title); - } - body.append("

    " - + String.format("
    相关资讯
      %s
    ", - strRelative)); - } - body.append("
    "); - // 封尾 - body.append("
    "); - return body.toString(); - } - - @Override - protected void showCommentView() { - if (mDetail != null) - UIHelper.showComment(getActivity(), mId, - CommentList.CATALOG_NEWS); - } - - @Override - protected int getCommentType() { - return CommentList.CATALOG_NEWS; - } - - @Override - protected int getFavoriteTargetType() { - return FavoriteList.TYPE_NEWS; - } - - @Override - protected String getShareTitle() { - return mDetail.getTitle(); - } - - @Override - protected String getShareContent() { - return StringUtils.getSubString(0, 55, - getFilterHtmlBody(mDetail.getBody())); - } - - @Override - protected String getShareUrl() { - return mDetail.getUrl().replace("http://www", "http://m"); - } - - @Override - protected int getFavoriteState() { - return mDetail.getFavorite(); - } - - @Override - protected void updateFavoriteChanged(int newFavoritedState) { - mDetail.setFavorite(newFavoritedState); - saveCache(mDetail); - } - - @Override - protected int getCommentCount() { - return mDetail.getCommentCount(); - } -} diff --git a/app/src/main/java/net/oschina/app/fragment/NewsFragment.java b/app/src/main/java/net/oschina/app/fragment/NewsFragment.java deleted file mode 100644 index c52d3a57b28ed372c12e58da0dd65832d833ba4c..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/fragment/NewsFragment.java +++ /dev/null @@ -1,106 +0,0 @@ -package net.oschina.app.fragment; - -import java.io.InputStream; -import java.io.Serializable; -import java.util.List; - -import net.oschina.app.adapter.NewsAdapter; -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.base.BaseListFragment; -import net.oschina.app.base.ListBaseAdapter; -import net.oschina.app.bean.News; -import net.oschina.app.bean.NewsList; -import net.oschina.app.interf.OnTabReselectListener; -import net.oschina.app.ui.empty.EmptyLayout; -import net.oschina.app.util.UIHelper; -import net.oschina.app.util.XmlUtils; -import android.view.View; -import android.widget.AdapterView; - -/** - * 新闻资讯 - * - * @author FireAnt(http://my.oschina.net/LittleDY) - * @created 2014年11月12日 下午4:17:45 - * - */ -public class NewsFragment extends BaseListFragment implements - OnTabReselectListener { - - protected static final String TAG = NewsFragment.class.getSimpleName(); - private static final String CACHE_KEY_PREFIX = "newslist_"; - - @Override - protected NewsAdapter getListAdapter() { - return new NewsAdapter(); - } - - @Override - protected String getCacheKeyPrefix() { - return CACHE_KEY_PREFIX + mCatalog; - } - - @Override - protected NewsList parseList(InputStream is) throws Exception { - NewsList list = null; - try { - list = XmlUtils.toBean(NewsList.class, is); - } catch (NullPointerException e) { - list = new NewsList(); - } - return list; - } - - @Override - protected NewsList readList(Serializable seri) { - return ((NewsList) seri); - } - - @Override - protected void sendRequestData() { - OSChinaApi.getNewsList(mCatalog, mCurrentPage, mHandler); - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, - long id) { - News news = mAdapter.getItem(position); - if (news != null) { - UIHelper.showNewsRedirect(view.getContext(), news); - - // 放入已读列表 - saveToReadedList(view, NewsList.PREF_READED_NEWS_LIST, news.getId() - + ""); - } - } - - @Override - protected void executeOnLoadDataSuccess(List data) { - if (mCatalog == NewsList.CATALOG_WEEK - || mCatalog == NewsList.CATALOG_MONTH) { - mErrorLayout.setErrorType(EmptyLayout.HIDE_LAYOUT); - if (mState == STATE_REFRESH) - mAdapter.clear(); - mAdapter.addData(data); - mState = STATE_NOMORE; - mAdapter.setState(ListBaseAdapter.STATE_NO_MORE); - return; - } - super.executeOnLoadDataSuccess(data); - } - - @Override - public void onTabReselect() { - onRefresh(); - } - - @Override - protected long getAutoRefreshTime() { - // 最新资讯两小时刷新一次 - if (mCatalog == NewsList.CATALOG_ALL) { - - return 2 * 60 * 60; - } - return super.getAutoRefreshTime(); - } -} diff --git a/app/src/main/java/net/oschina/app/fragment/PostDetailFragment.java b/app/src/main/java/net/oschina/app/fragment/PostDetailFragment.java deleted file mode 100644 index fe4e6ede8de76602f0b71c4333755ac5e67b18b2..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/fragment/PostDetailFragment.java +++ /dev/null @@ -1,129 +0,0 @@ -package net.oschina.app.fragment; - -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.base.CommonDetailFragment; -import net.oschina.app.bean.CommentList; -import net.oschina.app.bean.FavoriteList; -import net.oschina.app.bean.Post; -import net.oschina.app.bean.PostDetail; -import net.oschina.app.ui.DetailActivity; -import net.oschina.app.util.StringUtils; -import net.oschina.app.util.ThemeSwitchUtils; -import net.oschina.app.util.UIHelper; -import net.oschina.app.util.URLsUtils; -import net.oschina.app.util.XmlUtils; - -import java.io.InputStream; -import java.net.URLEncoder; - -/** - * Created by 火蚁 on 15/5/25. - */ -public class PostDetailFragment extends CommonDetailFragment { - @Override - protected String getCacheKey() { - return "post_" + mId; - } - - @Override - protected void sendRequestDataForNet() { - OSChinaApi.getPostDetail(mId, mDetailHeandler); - } - - @Override - protected Post parseData(InputStream is) { - return XmlUtils.toBean(PostDetail.class, is).getPost(); - } - - @Override - protected String getWebViewBody(Post detail) { - StringBuffer body = new StringBuffer(); - body.append(UIHelper.WEB_STYLE).append(UIHelper.WEB_LOAD_IMAGES); - body.append(ThemeSwitchUtils.getWebViewBodyString()); - // 添加title - body.append(String.format("
    %s
    ", mDetail.getTitle())); - // 添加作者和时间 - String time = StringUtils.friendly_time(mDetail.getPubDate()); - String author = String.format("%s", mDetail.getAuthorId(), mDetail.getAuthor()); - body.append(String.format("
    %s    %s
    ", author, time)); - // 添加图片点击放大支持 - body.append(UIHelper.setHtmlCotentSupportImagePreview(mDetail.getBody())); - body.append(getPostTags(mDetail.getTags())); - // 封尾 - body.append(""); - return body.toString(); - } - - @SuppressWarnings("deprecation") - private String getPostTags(Post.Tags taglist) { - if (taglist == null) - return ""; - StringBuffer tags = new StringBuffer(); - for (String tag : taglist.getTags()) { - tags.append(String - .format(" %s   ", - URLEncoder.encode(tag), tag)); - } - return String.format("
    %s
    ", tags); - } - - @Override - protected void showCommentView() { - if (mDetail != null) { - UIHelper.showComment(getActivity(), mId, CommentList.CATALOG_POST); - } - } - - @Override - protected int getCommentType() { - return CommentList.CATALOG_POST; - } - - @Override - protected String getShareTitle() { - return mDetail.getTitle(); - } - - @Override - protected String getShareContent() { - return StringUtils.getSubString(0, 55, - getFilterHtmlBody(mDetail.getBody())); - } - - @Override - protected String getShareUrl() { - return String.format(URLsUtils.URL_MOBILE + "question/%s_%s", mDetail.getAuthorId(), mId); - } - - @Override - protected int getFavoriteTargetType() { - return FavoriteList.TYPE_POST; - } - - @Override - protected int getFavoriteState() { - return mDetail.getFavorite(); - } - - @Override - protected void updateFavoriteChanged(int newFavoritedState) { - mDetail.setFavorite(newFavoritedState); - saveCache(mDetail); - } - - @Override - protected int getCommentCount() { - return mDetail.getAnswerCount(); - } - - @Override - public void onResume() { - super.onResume(); - ((DetailActivity) getActivity()).toolFragment.showReportButton(); - } - - @Override - protected String getRepotrUrl() { - return mDetail.getUrl(); - } -} diff --git a/app/src/main/java/net/oschina/app/fragment/PostsFragment.java b/app/src/main/java/net/oschina/app/fragment/PostsFragment.java deleted file mode 100644 index 03939793102bc4dbbc19ea2af392358201c90f57..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/fragment/PostsFragment.java +++ /dev/null @@ -1,64 +0,0 @@ -package net.oschina.app.fragment; - -import java.io.InputStream; -import java.io.Serializable; - -import net.oschina.app.adapter.PostAdapter; -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.base.BaseListFragment; -import net.oschina.app.bean.Post; -import net.oschina.app.bean.PostList; -import net.oschina.app.util.UIHelper; -import net.oschina.app.util.XmlUtils; -import android.view.View; -import android.widget.AdapterView; - -/** - * 问答 - * - * @author william_sim - */ -public class PostsFragment extends BaseListFragment { - - protected static final String TAG = PostsFragment.class.getSimpleName(); - private static final String CACHE_KEY_PREFIX = "postslist_"; - - @Override - protected PostAdapter getListAdapter() { - return new PostAdapter(); - } - - @Override - protected String getCacheKeyPrefix() { - return CACHE_KEY_PREFIX + mCatalog; - } - - @Override - protected PostList parseList(InputStream is) throws Exception { - PostList list = XmlUtils.toBean(PostList.class, is); - return list; - } - - @Override - protected PostList readList(Serializable seri) { - return ((PostList) seri); - } - - @Override - protected void sendRequestData() { - OSChinaApi.getPostList(mCatalog, mCurrentPage, mHandler); - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, - long id) { - Post post = mAdapter.getItem(position); - if (post != null) { - UIHelper.showPostDetail(view.getContext(), post.getId(), - post.getAnswerCount()); - // 放入已读列表 - saveToReadedList(view, PostList.PREF_READED_POST_LIST, post.getId() - + ""); - } - } -} diff --git a/app/src/main/java/net/oschina/app/fragment/QuestionTagFragment.java b/app/src/main/java/net/oschina/app/fragment/QuestionTagFragment.java index 7f002b30d48a1f68b2608115ebd1a711dc2fe156..169a00edc9bf041bdc908a364d23259c5f11f6ec 100644 --- a/app/src/main/java/net/oschina/app/fragment/QuestionTagFragment.java +++ b/app/src/main/java/net/oschina/app/fragment/QuestionTagFragment.java @@ -1,7 +1,8 @@ package net.oschina.app.fragment; -import java.io.InputStream; -import java.io.Serializable; +import android.os.Bundle; +import android.view.View; +import android.widget.AdapterView; import net.oschina.app.R; import net.oschina.app.adapter.PostAdapter; @@ -12,15 +13,14 @@ import net.oschina.app.bean.Post; import net.oschina.app.bean.PostList; import net.oschina.app.util.UIHelper; import net.oschina.app.util.XmlUtils; -import android.os.Bundle; -import android.view.View; -import android.widget.AdapterView; + +import java.io.InputStream; +import java.io.Serializable; /** * 标签相关帖子 * * @author FireAnt(http://my.oschina.net/LittleDY) - * @created 2014年11月6日 下午3:39:07 * */ public class QuestionTagFragment extends BaseListFragment { @@ -49,13 +49,12 @@ public class QuestionTagFragment extends BaseListFragment { @Override protected String getCacheKeyPrefix() { - return new StringBuffer(CACHE_KEY_PREFIX).append(mTag).toString(); + return CACHE_KEY_PREFIX + mTag; } @Override protected PostList parseList(InputStream is) throws Exception { - PostList list = XmlUtils.toBean(PostList.class, is); - return list; + return XmlUtils.toBean(PostList.class, is); } @Override diff --git a/app/src/main/java/net/oschina/app/fragment/SearchFragment.java b/app/src/main/java/net/oschina/app/fragment/SearchFragment.java deleted file mode 100644 index 3b9055ab075b969114f9977a5fa80cfc89edc8a6..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/fragment/SearchFragment.java +++ /dev/null @@ -1,93 +0,0 @@ -package net.oschina.app.fragment; - -import android.os.Bundle; -import android.view.View; -import android.view.WindowManager; -import android.widget.AdapterView; - -import net.oschina.app.adapter.SearchAdapter; -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.base.BaseListFragment; -import net.oschina.app.bean.SearchList; -import net.oschina.app.bean.SearchResult; -import net.oschina.app.ui.empty.EmptyLayout; -import net.oschina.app.util.UIHelper; -import net.oschina.app.util.XmlUtils; - -import java.io.InputStream; -import java.io.Serializable; - -public class SearchFragment extends BaseListFragment { - protected static final String TAG = SearchFragment.class.getSimpleName(); - private static final String CACHE_KEY_PREFIX = "search_list_"; - private String mCatalog; - private String mSearch; - private boolean mRquestDataIfCreated = false; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - Bundle args = getArguments(); - if (args != null) { - mCatalog = args.getString(BUNDLE_KEY_CATALOG); - } - int mode = WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN - | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN; - getActivity().getWindow().setSoftInputMode(mode); - } - - public void search(String search) { - mSearch = search; - if (mErrorLayout != null) { - mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING); - mState = STATE_REFRESH; - requestData(true); - } else { - mRquestDataIfCreated = true; - } - } - - @Override - protected boolean requestDataIfViewCreated() { - return mRquestDataIfCreated; - } - - @Override - protected SearchAdapter getListAdapter() { - return new SearchAdapter(); - } - - @Override - protected String getCacheKeyPrefix() { - return CACHE_KEY_PREFIX + mCatalog + mSearch; - } - - @Override - protected SearchList parseList(InputStream is) throws Exception { - SearchList list = XmlUtils.toBean(SearchList.class, is); - return list; - } - - @Override - protected SearchList readList(Serializable seri) { - return ((SearchList) seri); - } - - @Override - protected void sendRequestData() { - OSChinaApi.getSearchList(mCatalog, mSearch, mCurrentPage, mHandler); - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, - long id) { - SearchResult res = mAdapter.getItem(position); - if (res != null) { - if (res.getType().equalsIgnoreCase(SearchList.CATALOG_SOFTWARE)) { - UIHelper.showSoftwareDetailById(getActivity(), res.getId()); - } else { - UIHelper.showUrlRedirect(getActivity(), res.getUrl()); - } - } - } -} diff --git a/app/src/main/java/net/oschina/app/fragment/SettingsFragment.java b/app/src/main/java/net/oschina/app/fragment/SettingsFragment.java index 9df9372bdad1428eb4482779bf3a4fcba06efad1..00c216321afd2e1c8ee9bad912cad59052d190fb 100644 --- a/app/src/main/java/net/oschina/app/fragment/SettingsFragment.java +++ b/app/src/main/java/net/oschina/app/fragment/SettingsFragment.java @@ -1,54 +1,80 @@ package net.oschina.app.fragment; +import android.Manifest; +import android.annotation.SuppressLint; import android.content.DialogInterface; +import android.content.Intent; +import android.os.Build; import android.os.Bundle; +import android.provider.Settings; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.RelativeLayout; import android.widget.TextView; import net.oschina.app.AppConfig; import net.oschina.app.AppContext; -import net.oschina.app.AppManager; import net.oschina.app.R; import net.oschina.app.base.BaseFragment; -import net.oschina.app.util.DialogHelp; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.account.activity.LoginActivity; +import net.oschina.app.improve.bean.Version; +import net.oschina.app.improve.main.FeedBackActivity; +import net.oschina.app.improve.main.update.CheckUpdateManager; +import net.oschina.app.improve.main.update.DownloadService; +import net.oschina.app.improve.utils.DialogHelper; +import net.oschina.app.improve.widget.togglebutton.ToggleButton; +import net.oschina.app.improve.widget.togglebutton.ToggleButton.OnToggleChanged; import net.oschina.app.util.FileUtil; import net.oschina.app.util.MethodsCompat; import net.oschina.app.util.UIHelper; -import net.oschina.app.widget.togglebutton.ToggleButton; -import net.oschina.app.widget.togglebutton.ToggleButton.OnToggleChanged; import org.kymjs.kjframe.http.HttpConfig; import java.io.File; +import java.util.List; +import butterknife.Bind; import butterknife.ButterKnife; -import butterknife.InjectView; +import pub.devrel.easypermissions.AfterPermissionGranted; +import pub.devrel.easypermissions.EasyPermissions; /** * 系统设置界面 * * @author kymjs */ -public class SettingsFragment extends BaseFragment { +public class SettingsFragment extends BaseFragment implements EasyPermissions.PermissionCallbacks, CheckUpdateManager.RequestPermissions { - @InjectView(R.id.tb_loading_img) + private static final int RC_EXTERNAL_STORAGE = 0x04;//存储权限 + + @Bind(R.id.tb_loading_img) ToggleButton mTbLoadImg; - @InjectView(R.id.tv_cache_size) + @Bind(R.id.tv_cache_size) TextView mTvCacheSize; - @InjectView(R.id.setting_logout) - TextView mTvExit; - @InjectView(R.id.tb_double_click_exit) + //@Bind(R.id.setting_logout) + // TextView mTvExit; + @Bind(R.id.rl_check_version) + RelativeLayout mRlCheck_version; + @Bind(R.id.tb_double_click_exit) ToggleButton mTbDoubleClickExit; + @Bind(R.id.setting_line_top) + View mSettingLineTop; + @Bind(R.id.setting_line_bottom) + View mSettingLineBottom; + private RelativeLayout mCancel; + + private Version mVersion; @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_settings, container, false); - ButterKnife.inject(this, view); + ButterKnife.bind(this, view); initView(view); initData(); return view; @@ -71,16 +97,18 @@ public class SettingsFragment extends BaseFragment { }); view.findViewById(R.id.rl_loading_img).setOnClickListener(this); - view.findViewById(R.id.rl_notification_settings).setOnClickListener( - this); view.findViewById(R.id.rl_clean_cache).setOnClickListener(this); view.findViewById(R.id.rl_double_click_exit).setOnClickListener(this); view.findViewById(R.id.rl_about).setOnClickListener(this); - view.findViewById(R.id.rl_exit).setOnClickListener(this); + view.findViewById(R.id.rl_check_version).setOnClickListener(this); + // view.findViewById(R.id.rl_exit).setOnClickListener(this); + view.findViewById(R.id.rl_feedback).setOnClickListener(this); + mCancel = (RelativeLayout) view.findViewById(R.id.rl_cancle); + mCancel.setOnClickListener(this); - if (!AppContext.getInstance().isLogin()) { - mTvExit.setText("退出"); - } + // if (!AppContext.getInstance().isLogin()) { + // mTvExit.setText("退出"); + // } } @Override @@ -96,14 +124,28 @@ public class SettingsFragment extends BaseFragment { } else { mTbDoubleClickExit.setToggleOff(); } + calculateCacheSize(); + } - caculateCacheSize(); + @Override + public void onResume() { + super.onResume(); + boolean login = AccountHelper.isLogin(); + if (!login) { + mCancel.setVisibility(View.INVISIBLE); + mSettingLineTop.setVisibility(View.INVISIBLE); + mSettingLineBottom.setVisibility(View.INVISIBLE); + } else { + mCancel.setVisibility(View.VISIBLE); + mSettingLineTop.setVisibility(View.VISIBLE); + mSettingLineBottom.setVisibility(View.VISIBLE); + } } /** * 计算缓存的大小 */ - private void caculateCacheSize() { + private void calculateCacheSize() { long fileSize = 0; String cacheSize = "0KB"; File filesDir = getActivity().getFilesDir(); @@ -132,20 +174,41 @@ public class SettingsFragment extends BaseFragment { case R.id.rl_loading_img: mTbLoadImg.toggle(); break; - case R.id.rl_notification_settings: - UIHelper.showSettingNotification(getActivity()); - break; case R.id.rl_clean_cache: onClickCleanCache(); break; case R.id.rl_double_click_exit: mTbDoubleClickExit.toggle(); break; + case R.id.rl_feedback: + //UIHelper.showSimpleBack(getActivity(), SimpleBackPage.FEED_BACK); + if (!AccountHelper.isLogin()) { + LoginActivity.show(getContext()); + return; + } + FeedBackActivity.show(getActivity()); + break; case R.id.rl_about: UIHelper.showAboutOSC(getActivity()); break; - case R.id.rl_exit: - onClickExit(); + case R.id.rl_check_version: + onClickUpdate(); + break; +// case R.id.rl_exit: +// // onClickExit(); +// break; + case R.id.rl_cancle: + // 清理所有缓存 + UIHelper.clearAppCache(false); + // 注销操作 + AccountHelper.logout(mCancel, new Runnable() { + @Override + public void run() { + //getActivity().finish(); + mTvCacheSize.setText("0KB"); + AppContext.showToastShort(getString(R.string.logout_success_hint)); + } + }); break; default: break; @@ -153,12 +216,18 @@ public class SettingsFragment extends BaseFragment { } + private void onClickUpdate() { + CheckUpdateManager manager = new CheckUpdateManager(getActivity(), true); + manager.setCaller(this); + manager.checkUpdate(); + } + private void onClickCleanCache() { - DialogHelp.getConfirmDialog(getActivity(), "是否清空缓存?", new DialogInterface.OnClickListener + DialogHelper.getConfirmDialog(getActivity(), "是否清空缓存?", new DialogInterface.OnClickListener () { @Override public void onClick(DialogInterface dialogInterface, int i) { - UIHelper.clearAppCache(getActivity()); + UIHelper.clearAppCache(true); mTvCacheSize.setText("0KB"); } }).show(); @@ -168,7 +237,48 @@ public class SettingsFragment extends BaseFragment { AppContext .set(AppConfig.KEY_NOTIFICATION_DISABLE_WHEN_EXIT, false); - AppManager.getAppManager().AppExit(getActivity()); - getActivity().finish(); + //getActivity().finish(); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + getActivity().finishAffinity(); + } + } + + @Override + public void call(Version version) { + this.mVersion = version; + requestExternalStorage(); + } + + @SuppressLint("InlinedApi") + @AfterPermissionGranted(RC_EXTERNAL_STORAGE) + public void requestExternalStorage() { + if (EasyPermissions.hasPermissions(getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE)) { + DownloadService.startService(getActivity(), mVersion.getDownloadUrl()); + } else { + EasyPermissions.requestPermissions(this, "", RC_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE); + } + } + + + @Override + public void onPermissionsGranted(int requestCode, List perms) { + + } + + @Override + public void onPermissionsDenied(int requestCode, List perms) { + DialogHelper.getConfirmDialog(getActivity(), "温馨提示", "需要开启开源中国对您手机的存储权限才能下载安装,是否现在开启", "去开启", "取消", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + startActivity(new Intent(Settings.ACTION_APPLICATION_SETTINGS)); + } + }).show(); + } + + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); } } diff --git a/app/src/main/java/net/oschina/app/fragment/SettingsNotificationFragment.java b/app/src/main/java/net/oschina/app/fragment/SettingsNotificationFragment.java deleted file mode 100644 index 11a22e4d6338fe84d48e2a5b2d7f958e99c5d803..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/fragment/SettingsNotificationFragment.java +++ /dev/null @@ -1,90 +0,0 @@ -package net.oschina.app.fragment; - -import net.oschina.app.AppConfig; -import net.oschina.app.AppContext; -import net.oschina.app.R; -import net.oschina.app.base.BaseFragment; -import net.oschina.app.widget.togglebutton.ToggleButton; -import net.oschina.app.widget.togglebutton.ToggleButton.OnToggleChanged; -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import butterknife.ButterKnife; -import butterknife.InjectView; - -public class SettingsNotificationFragment extends BaseFragment { - - @InjectView(R.id.tb_accept) ToggleButton mTbAccept; - @InjectView(R.id.tb_voice) ToggleButton mTbVoice; - @InjectView(R.id.tb_vibration) ToggleButton mTbVibration; - @InjectView(R.id.tb_app_exit) ToggleButton mTbAppExit; - - @Override - public View onCreateView(LayoutInflater inflater, - @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_settings_notifcation, container, - false); - ButterKnife.inject(this, view); - initView(view); - initData(); - return view; - } - - @Override - public void initView(View view) { - setToggleChanged(mTbAccept, AppConfig.KEY_NOTIFICATION_ACCEPT); - setToggleChanged(mTbVoice, AppConfig.KEY_NOTIFICATION_SOUND); - setToggleChanged(mTbVibration, AppConfig.KEY_NOTIFICATION_VIBRATION); - setToggleChanged(mTbAppExit, AppConfig.KEY_NOTIFICATION_DISABLE_WHEN_EXIT); - - view.findViewById(R.id.rl_accept).setOnClickListener(this); - view.findViewById(R.id.rl_voice).setOnClickListener(this); - view.findViewById(R.id.rl_vibration).setOnClickListener(this); - view.findViewById(R.id.rl_app_exit).setOnClickListener(this); - } - - public void initData() { - setToggle(AppContext.get(AppConfig.KEY_NOTIFICATION_ACCEPT, true), mTbAccept); - setToggle(AppContext.get(AppConfig.KEY_NOTIFICATION_SOUND, true), mTbVoice); - setToggle(AppContext.get(AppConfig.KEY_NOTIFICATION_VIBRATION, true), mTbVibration); - setToggle(AppContext.get(AppConfig.KEY_NOTIFICATION_DISABLE_WHEN_EXIT, true), mTbAppExit); - } - - private void setToggleChanged(ToggleButton tb, final String key) { - tb.setOnToggleChanged(new OnToggleChanged() { - - @Override - public void onToggle(boolean on) { - AppContext.set(key, on); - } - }); - } - - private void setToggle(boolean value, ToggleButton tb) { - if (value) - tb.setToggleOn(); - else - tb.setToggleOff(); - } - - @Override - public void onClick(View v) { - final int id = v.getId(); - switch (id) { - case R.id.rl_accept: - mTbAccept.toggle(); - break; - case R.id.rl_voice: - mTbVoice.toggle(); - break; - case R.id.rl_vibration: - mTbVibration.toggle(); - break; - case R.id.rl_app_exit: - mTbAppExit.toggle(); - break; - } - } -} diff --git a/app/src/main/java/net/oschina/app/fragment/SoftWareTweetsFrament.java b/app/src/main/java/net/oschina/app/fragment/SoftWareTweetsFrament.java deleted file mode 100644 index 067b922ac107e5a6250907fa78df63a61db1c00f..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/fragment/SoftWareTweetsFrament.java +++ /dev/null @@ -1,116 +0,0 @@ -package net.oschina.app.fragment; - -import java.io.InputStream; -import java.io.Serializable; - -import net.oschina.app.AppContext; -import net.oschina.app.R; -import net.oschina.app.adapter.TweetAdapter; -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.base.BaseActivity; -import net.oschina.app.base.BaseListFragment; -import net.oschina.app.bean.Tweet; -import net.oschina.app.bean.TweetsList; -import net.oschina.app.service.ServerTaskUtils; -import net.oschina.app.util.UIHelper; -import net.oschina.app.util.XmlUtils; -import android.app.Activity; -import android.os.Bundle; -import android.view.View; -import android.view.WindowManager; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemLongClickListener; - -public class SoftWareTweetsFrament extends BaseListFragment implements - OnItemLongClickListener { - - public static final String BUNDLE_KEY_ID = "BUNDLE_KEY_ID"; - protected static final String TAG = SoftWareTweetsFrament.class - .getSimpleName(); - private static final String CACHE_KEY_PREFIX = "software_tweet_list"; - - private int mId; - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - BaseActivity act = ((BaseActivity) activity); - try { - activity.findViewById(R.id.emoji_container).setVisibility( - View.VISIBLE); - } catch (NullPointerException e) { - } - } - - protected int getLayoutRes() { - return R.layout.fragment_pull_refresh_listview; - } - - @Override - public void initView(View view) { - super.initView(view); - mListView.setOnItemLongClickListener(this); - } - - @Override - public void onCreate(android.os.Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - Bundle args = getArguments(); - if (args != null) { - mId = args.getInt(BUNDLE_KEY_ID, 0); - } - - int mode = WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN - | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; - getActivity().getWindow().setSoftInputMode(mode); - } - - @Override - protected TweetAdapter getListAdapter() { - return new TweetAdapter(); - } - - @Override - protected String getCacheKeyPrefix() { - return new StringBuilder(CACHE_KEY_PREFIX).append("_").append(mId) - .toString(); - } - - @Override - protected TweetsList parseList(InputStream is) throws Exception { - return XmlUtils.toBean(TweetsList.class, is); - } - - @Override - protected TweetsList readList(Serializable seri) { - return ((TweetsList) seri); - } - - @Override - protected void sendRequestData() { - OSChinaApi.getSoftTweetList(mId, mCurrentPage, mHandler); - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, - long id) { - final Tweet tweet = mAdapter.getItem(position); - if (tweet == null) { - return; - } - UIHelper.showTweetDetail(parent.getContext(), tweet, tweet.getId()); - } - - private void handleComment(String text) { - Tweet tweet = new Tweet(); - tweet.setAuthorid(AppContext.getInstance().getLoginUid()); - tweet.setBody(text); - ServerTaskUtils.pubSoftWareTweet(getActivity(), tweet, mId); - } - - @Override - public boolean onItemLongClick(AdapterView parent, View view, - int position, long id) { - return true; - } -} diff --git a/app/src/main/java/net/oschina/app/fragment/SoftwareDetailFragment.java b/app/src/main/java/net/oschina/app/fragment/SoftwareDetailFragment.java deleted file mode 100644 index 6e76225e382bf07d115cb312b37a4dfa24fc2388..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/fragment/SoftwareDetailFragment.java +++ /dev/null @@ -1,196 +0,0 @@ -package net.oschina.app.fragment; - -import android.text.Editable; -import android.text.TextUtils; - -import net.oschina.app.AppContext; -import net.oschina.app.R; -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.base.CommonDetailFragment; -import net.oschina.app.bean.FavoriteList; -import net.oschina.app.bean.Software; -import net.oschina.app.bean.SoftwareDetail; -import net.oschina.app.bean.Tweet; -import net.oschina.app.util.StringUtils; -import net.oschina.app.util.TDevice; -import net.oschina.app.util.ThemeSwitchUtils; -import net.oschina.app.util.UIHelper; -import net.oschina.app.util.URLsUtils; -import net.oschina.app.util.XmlUtils; - -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; - -/** - * Created by 火蚁 on 15/5/26. - */ -public class SoftwareDetailFragment extends CommonDetailFragment { - - private String mIden; - - @Override - protected String getCacheKey() { - if (TextUtils.isEmpty(mIden)) { - return "software_" + mId; - } - return "software_" + mIden; - } - - @Override - protected void sendRequestDataForNet() { - // 通过id来获取软件详情 - if (mId > 0) { - OSChinaApi.getSoftwareDetail(mId, mDetailHeandler); - return; - } - - if (TextUtils.isEmpty(mIden)) { - executeOnLoadDataError(); - return; - } - OSChinaApi.getSoftwareDetail(mIden, mDetailHeandler); - } - - @Override - public void initData() { - super.initData(); - mIden = getActivity().getIntent().getStringExtra("ident"); - if (TextUtils.isEmpty(mIden)) { - return; - } - try { - mIden = URLEncoder.encode(mIden, "UTF-8"); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } - } - - @Override - protected Software parseData(InputStream is) { - return XmlUtils.toBean(SoftwareDetail.class, is).getSoftware(); - } - - @Override - protected String getWebViewBody(Software detail) { - mId = detail.getId(); - if (TextUtils.isEmpty(detail.getBody())) { - return ""; - } - StringBuffer body = new StringBuffer(); - body.append(ThemeSwitchUtils.getWebViewBodyString()); - body.append(UIHelper.WEB_STYLE).append(UIHelper.WEB_LOAD_IMAGES); - // 添加title - String title = ""; - // 判断是否推荐 - if (mDetail.getRecommended() == 4) { - title = String.format("
    %s %s
    ", mDetail.getLogo(), mDetail.getExtensionTitle(), mDetail.getTitle(), "file:///android_asset/ic_soft_recommend.png"); - } else { - title = String.format("
    %s %s
    ", mDetail.getLogo(), mDetail.getExtensionTitle(), mDetail.getTitle()); - } - body.append(title); - // 添加图片点击放大支持 - body.append(UIHelper.setHtmlCotentSupportImagePreview(mDetail.getBody())); - - // 软件信息 - body.append("
    "); - if (!TextUtils.isEmpty(mDetail.getAuthor())) { - String author = String.format("%s", mDetail.getAuthorId(), mDetail.getAuthor()); - body.append(String.format("
  • 软件作者:  %s
  • ", author)); - } - body.append(String.format("
  • 开源协议:  %s
  • ", mDetail.getLicense())); - body.append(String.format("
  • 开发语言:  %s
  • ", mDetail.getLanguage())); - body.append(String.format("
  • 操作系统:  %s
  • ", mDetail.getOs())); - body.append(String.format("
  • 收录时间:  %s
  • ", mDetail.getRecordtime())); - body.append("
    "); - - // 软件的首页、文档、下载 - body.append("
    "); - if (!TextUtils.isEmpty(mDetail.getHomepage())) { - body.append(String.format("
  • 软件首页
  • ", mDetail.getHomepage())); - } - if (!TextUtils.isEmpty(mDetail.getDocument())) { - body.append(String.format("
  • 软件文档
  • ", mDetail.getDocument())); - } - if (!TextUtils.isEmpty(mDetail.getDownload())) { - body.append(String.format("
  • 软件下载
  • ", mDetail.getDownload())); - } - body.append("
    "); - // 封尾 - body.append(""); - return body.toString(); - } - - @Override - protected void showCommentView() { - if (mDetail != null) - UIHelper.showSoftWareTweets(getActivity(), mDetail.getId()); - } - - @Override - public void onClickSendButton(Editable str) { - if (mDetail.getId() == 0) { - AppContext.showToast("无法获取该软件~"); - return; - } - if (!TDevice.hasInternet()) { - AppContext.showToastShort(R.string.tip_network_error); - return; - } - if (!AppContext.getInstance().isLogin()) { - UIHelper.showLoginActivity(getActivity()); - return; - } - if (TextUtils.isEmpty(str)) { - AppContext.showToastShort(R.string.tip_comment_content_empty); - return; - } - Tweet tweet = new Tweet(); - tweet.setAuthorid(AppContext.getInstance().getLoginUid()); - tweet.setBody(str.toString()); - showWaitDialog(R.string.progress_submit); - OSChinaApi.pubSoftWareTweet(tweet, mDetail.getId(), mCommentHandler); - } - - @Override - protected int getCommentType() { - return 0; - } - - @Override - protected int getFavoriteTargetType() { - return FavoriteList.TYPE_SOFTWARE; - } - - @Override - protected int getFavoriteState() { - return mDetail.getFavorite(); - } - - @Override - protected void updateFavoriteChanged(int newFavoritedState) { - mDetail.setFavorite(newFavoritedState); - saveCache(mDetail); - } - - @Override - protected int getCommentCount() { - return mDetail.getTweetCount(); - } - - @Override - protected String getShareTitle() { - return String.format("%s %s", mDetail.getExtensionTitle(), mDetail.getTitle()); - } - - @Override - protected String getShareContent() { - return StringUtils.getSubString(0, 55, - getFilterHtmlBody(mDetail.getBody())); - } - - @Override - protected String getShareUrl() { - return String.format(URLsUtils.URL_MOBILE + "p/%s", mIden); - } -} diff --git a/app/src/main/java/net/oschina/app/fragment/SoftwareListFragment.java b/app/src/main/java/net/oschina/app/fragment/SoftwareListFragment.java index 266682c0aa08b12e168aec2ede8d086b8a6fd2a0..7100881e458c9709f0c228af6cec32c12dca14e7 100644 --- a/app/src/main/java/net/oschina/app/fragment/SoftwareListFragment.java +++ b/app/src/main/java/net/oschina/app/fragment/SoftwareListFragment.java @@ -1,8 +1,8 @@ package net.oschina.app.fragment; -import java.io.InputStream; -import java.io.Serializable; -import java.util.List; +import android.os.Bundle; +import android.view.View; +import android.widget.AdapterView; import net.oschina.app.adapter.SoftwareAdapter; import net.oschina.app.api.remote.OSChinaApi; @@ -11,82 +11,84 @@ import net.oschina.app.bean.Entity; import net.oschina.app.bean.ListEntity; import net.oschina.app.bean.SoftwareDec; import net.oschina.app.bean.SoftwareList; -import net.oschina.app.util.UIHelper; +import net.oschina.app.improve.detail.activities.SoftwareDetailActivity; import net.oschina.app.util.XmlUtils; -import android.os.Bundle; -import android.view.View; -import android.widget.AdapterView; + +import java.io.InputStream; +import java.io.Serializable; +import java.util.List; public class SoftwareListFragment extends BaseListFragment { public static final String BUNDLE_SOFTWARE = "BUNDLE_SOFTWARE"; - protected static final String TAG = SoftwareListFragment.class - .getSimpleName(); private static final String CACHE_KEY_PREFIX = "softwarelist_"; private String softwareType = "recommend"; + @Override public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - Bundle args = getArguments(); - if (args != null) { - softwareType = args.getString(BUNDLE_SOFTWARE); - } + super.onCreate(savedInstanceState); + Bundle args = getArguments(); + if (args != null) { + softwareType = args.getString(BUNDLE_SOFTWARE); + } } @Override protected SoftwareAdapter getListAdapter() { - return new SoftwareAdapter(); + return new SoftwareAdapter(); } @Override protected String getCacheKeyPrefix() { - return CACHE_KEY_PREFIX + softwareType; + return CACHE_KEY_PREFIX + softwareType; } @Override protected SoftwareList parseList(InputStream is) throws Exception { - SoftwareList list = XmlUtils.toBean(SoftwareList.class, is); - return list; + SoftwareList list = XmlUtils.toBean(SoftwareList.class, is); + return list; } @Override protected ListEntity readList(Serializable seri) { - return ((SoftwareList) seri); + return ((SoftwareList) seri); } @Override protected void sendRequestData() { - OSChinaApi.getSoftwareList(softwareType, mCurrentPage, mHandler); + OSChinaApi.getSoftwareList(softwareType, mCurrentPage, mHandler); } @Override public void onItemClick(AdapterView parent, View view, int position, - long id) { - SoftwareDec softwaredec = (SoftwareDec) mAdapter.getItem(position); - if (softwaredec != null) { - String ident = softwaredec.getUrl().substring(softwaredec.getUrl().lastIndexOf("/") + 1); - UIHelper.showSoftwareDetail(getActivity(), ident); - // 放入已读列表 - saveToReadedList(view, SoftwareList.PREF_READED_SOFTWARE_LIST, - softwaredec.getName()); - } + long id) { + SoftwareDec softwaredec = mAdapter.getItem(position); + if (softwaredec != null) { + // String ident = softwaredec.getUrl().substring(softwaredec.getUrl().lastIndexOf("/") + 1); + int softwareDecId = softwaredec.getId(); + //SoftwareDetailActivity.show(getActivity(), ident); + SoftwareDetailActivity.show(getActivity(), softwareDecId); + // 放入已读列表 + saveToReadedList(view, SoftwareList.PREF_READED_SOFTWARE_LIST, + softwaredec.getName()); + } } @Override protected boolean compareTo(List data, Entity enity) { - int s = data.size(); - if (enity != null) { - for (int i = 0; i < s; i++) { - if (((SoftwareDec) enity).getName().equals( - ((SoftwareDec) data.get(i)).getName())) { - return true; - } - } - } - return false; + int s = data.size(); + if (enity != null) { + for (int i = 0; i < s; i++) { + if (((SoftwareDec) enity).getName().equals( + ((SoftwareDec) data.get(i)).getName())) { + return true; + } + } + } + return false; } } diff --git a/app/src/main/java/net/oschina/app/fragment/TweetDetailFragment.java b/app/src/main/java/net/oschina/app/fragment/TweetDetailFragment.java deleted file mode 100644 index b200143e8194e0b0554c828fe7cc9a90491d0190..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/fragment/TweetDetailFragment.java +++ /dev/null @@ -1,548 +0,0 @@ -package net.oschina.app.fragment; - -import android.content.DialogInterface; -import android.content.Intent; -import android.graphics.drawable.AnimationDrawable; -import android.os.Bundle; -import android.text.Editable; -import android.text.TextUtils; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.webkit.WebView; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.AdapterView.OnItemLongClickListener; -import android.widget.ImageView; -import android.widget.RelativeLayout; -import android.widget.TextView; - -import com.loopj.android.http.AsyncHttpResponseHandler; - -import net.oschina.app.AppContext; -import net.oschina.app.R; -import net.oschina.app.adapter.CommentAdapter; -import net.oschina.app.api.OperationResponseHandler; -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.base.BeseHaveHeaderListFragment; -import net.oschina.app.base.ListBaseAdapter; -import net.oschina.app.bean.Comment; -import net.oschina.app.bean.CommentList; -import net.oschina.app.bean.Result; -import net.oschina.app.bean.ResultBean; -import net.oschina.app.bean.Tweet; -import net.oschina.app.bean.TweetDetail; -import net.oschina.app.cache.CacheManager; -import net.oschina.app.emoji.OnSendClickListener; -import net.oschina.app.ui.DetailActivity; -import net.oschina.app.ui.empty.EmptyLayout; -import net.oschina.app.util.DialogHelp; -import net.oschina.app.util.HTMLUtil; -import net.oschina.app.util.KJAnimations; -import net.oschina.app.util.PlatfromUtil; -import net.oschina.app.util.StringUtils; -import net.oschina.app.util.TDevice; -import net.oschina.app.util.ThemeSwitchUtils; -import net.oschina.app.util.TypefaceUtils; -import net.oschina.app.util.UIHelper; -import net.oschina.app.util.XmlUtils; -import net.oschina.app.widget.AvatarView; -import net.oschina.app.widget.RecordButtonUtil; -import net.oschina.app.widget.RecordButtonUtil.OnPlayListener; - -import cz.msebera.android.httpclient.Header; -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.io.Serializable; -import java.util.List; - -/*** - * 动弹详情,实际每个item显示的数据类型是Comment - * - * TweetDetailFragment.java - * - * @author 火蚁(http://my.oschina.net/u/253900) - * - * @data 2015-1-28 上午11:48:41 - */ -public class TweetDetailFragment extends - BeseHaveHeaderListFragment implements - OnItemClickListener, OnItemLongClickListener, OnSendClickListener { - - private static final String CACHE_KEY_PREFIX = "tweet_"; - private static final String CACHE_KEY_TWEET_COMMENT = "tweet_comment_"; - private AvatarView mIvAvatar; - private TextView mTvName, mTvFrom, mTvTime, mTvCommentCount; - private WebView mContent; - private int mTweetId; - private Tweet mTweet; - private RelativeLayout mRlRecordSound; - private final RecordButtonUtil util = new RecordButtonUtil(); - - private TextView mLikeUser; - private TextView mTvLikeState; - - private DetailActivity outAty; - - @Override - protected CommentAdapter getListAdapter() { - return new CommentAdapter(); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - outAty = (DetailActivity) getActivity(); - return super.onCreateView(inflater, container, savedInstanceState); - } - - @Override - protected String getCacheKeyPrefix() { - return CACHE_KEY_TWEET_COMMENT + mTweetId + "_" + mCurrentPage; - } - - @Override - protected CommentList parseList(InputStream is) throws Exception { - CommentList list = XmlUtils.toBean(CommentList.class, is); - return list; - } - - @Override - protected CommentList readList(Serializable seri) { - return ((CommentList) seri); - } - - @Override - protected void sendRequestData() { - OSChinaApi.getCommentList(mTweetId, CommentList.CATALOG_TWEET, - mCurrentPage, mHandler); - } - - /** - * 初始化声音动弹的录音View - * - * @param header - */ - private void initSoundView(View header) { - final ImageView playerButton = (ImageView) header - .findViewById(R.id.tweet_img_record); - final TextView playerTime = (TextView) header - .findViewById(R.id.tweet_tv_record); - final AnimationDrawable drawable = (AnimationDrawable) playerButton - .getBackground(); - mRlRecordSound = (RelativeLayout) header - .findViewById(R.id.tweet_bg_record); - mRlRecordSound.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (mTweet != null) { - util.startPlay(mTweet.getAttach(), playerTime); - } else { - AppContext.showToast("找不到语音动弹,可能已经被主人删除了"); - } - } - }); - - util.setOnPlayListener(new OnPlayListener() { - @SuppressWarnings("deprecation") - @Override - public void stopPlay() { - drawable.stop(); - playerButton.setBackgroundDrawable(drawable.getFrame(0)); - } - - @SuppressWarnings("deprecation") - @Override - public void starPlay() { - playerButton.setBackgroundDrawable(drawable); - drawable.start(); - } - }); - } - - @Override - public void onStop() { - super.onStop(); - if (util != null && util.isPlaying()) { - util.stopPlay(); - } - } - - @Override - protected boolean requestDataIfViewCreated() { - return false; - } - - @Override - public void onResume() { - super.onResume(); - outAty.emojiFragment.hideFlagButton(); - } - - private void fillUI() { - mIvAvatar.setAvatarUrl(mTweet.getPortrait()); - mIvAvatar.setUserInfo(mTweet.getAuthorid(), mTweet.getAuthor()); - mTvName.setText(mTweet.getAuthor()); - mTvTime.setText(StringUtils.friendly_time(mTweet.getPubDate())); - PlatfromUtil.setPlatFromString(mTvFrom, mTweet.getAppclient()); - - mTvCommentCount.setText(mTweet.getCommentCount() + ""); - if (StringUtils.isEmpty(mTweet.getAttach())) { - mRlRecordSound.setVisibility(View.GONE); - } else { - mRlRecordSound.setVisibility(View.VISIBLE); - } - fillWebViewBody(); - setLikeUser(); - setLikeState(); - } - - private void setLikeState() { - if (mTweet != null) { - if (mTweet.getIsLike() == 1) { - mTvLikeState.setTextColor(AppContext.getInstance().getResources().getColor(R.color.day_colorPrimary)); - } else { - mTvLikeState.setTextColor(AppContext.getInstance().getResources().getColor(R.color.gray)); - } - } - } - - private void setLikeUser() { - if (mTweet == null || mTweet.getLikeUser() == null - || mTweet.getLikeUser().isEmpty()) { - mLikeUser.setVisibility(View.GONE); - } else { - mLikeUser.setVisibility(View.VISIBLE); - mTweet.setLikeUsers(getActivity(), mLikeUser, false); - } - } - - /** - * 填充webview内容 - */ - private void fillWebViewBody() { - StringBuffer body = new StringBuffer(); - body.append(ThemeSwitchUtils.getWebViewBodyString()); - body.append(UIHelper.WEB_STYLE + UIHelper.WEB_LOAD_IMAGES); - - StringBuilder tweetbody = new StringBuilder(mTweet.getBody()); - - String tweetBody = TextUtils.isEmpty(mTweet.getImgSmall()) ? tweetbody - .toString() : tweetbody.toString() + "
    "; - body.append(setHtmlCotentSupportImagePreview(tweetBody)); - - UIHelper.addWebImageShow(getActivity(), mContent); - // 封尾 - body.append(""); - mContent.loadDataWithBaseURL(null, body.toString(), "text/html", - "utf-8", null); - } - - /** - * 添加图片放大支持 - * - * @param body - * @return - */ - private String setHtmlCotentSupportImagePreview(String body) { - // 过滤掉 img标签的width,height属性 - body = body.replaceAll("(]*?)\\s+width\\s*=\\s*\\S+", "$1"); - body = body.replaceAll("(]*?)\\s+height\\s*=\\s*\\S+", "$1"); - return body.replaceAll("(]+src=\")(\\S+)\"", - "$1$2\" onClick=\"javascript:mWebViewImageListener.showImagePreview('" - + mTweet.getImgBig() + "')\""); - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, - long id) { - final Comment comment = mAdapter.getItem(position - 1); - if (comment == null) - return; - outAty.emojiFragment.getEditText().setHint("回复:" + comment.getAuthor()); - outAty.emojiFragment.getEditText().setTag(comment); - outAty.emojiFragment.showSoftKeyboard(); - } - - private final AsyncHttpResponseHandler mCommentHandler = new AsyncHttpResponseHandler() { - - @Override - public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { - try { - ResultBean rsb = XmlUtils.toBean(ResultBean.class, - new ByteArrayInputStream(arg2)); - Result res = rsb.getResult(); - if (res.OK()) { - hideWaitDialog(); - AppContext.showToastShort(R.string.comment_publish_success); - mAdapter.setState(ListBaseAdapter.STATE_NO_MORE); - mAdapter.addItem(0, rsb.getComment()); - setTweetCommentCount(); - } else { - hideWaitDialog(); - AppContext.showToastShort(res.getErrorMessage()); - } - outAty.emojiFragment.clean(); - } catch (Exception e) { - e.printStackTrace(); - onFailure(arg0, arg1, arg2, e); - } - } - - @Override - public void onFailure(int arg0, Header[] arg1, byte[] arg2, - Throwable arg3) { - hideWaitDialog(); - AppContext.showToastShort(R.string.comment_publish_faile); - } - }; - - class DeleteOperationResponseHandler extends OperationResponseHandler { - - DeleteOperationResponseHandler(Object... args) { - super(args); - } - - @Override - public void onSuccess(int code, ByteArrayInputStream is, Object[] args) { - try { - Result res = XmlUtils.toBean(ResultBean.class, is).getResult(); - if (res.OK()) { - AppContext.showToastShort(R.string.delete_success); - mAdapter.removeItem(args[0]); - setTweetCommentCount(); - } else { - AppContext.showToastShort(res.getErrorMessage()); - } - } catch (Exception e) { - e.printStackTrace(); - onFailure(code, e.getMessage(), args); - } - } - - @Override - public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { - - } - - @Override - public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { - AppContext.showToastShort(R.string.delete_faile); - } - } - - private void handleDeleteComment(Comment comment) { - if (!AppContext.getInstance().isLogin()) { - UIHelper.showLoginActivity(getActivity()); - return; - } - AppContext.showToastShort(R.string.deleting); - OSChinaApi.deleteComment(mTweetId, CommentList.CATALOG_TWEET, - comment.getId(), comment.getAuthorId(), - new DeleteOperationResponseHandler(comment)); - } - - private void setTweetCommentCount() { - mAdapter.notifyDataSetChanged(); - if (mTweet != null) { - mTweet.setCommentCount(mAdapter.getDataSize() + ""); - mTvCommentCount.setText(mTweet.getCommentCount() + ""); - } - } - - @Override - public boolean onItemLongClick(AdapterView parent, View view, - int position, long id) { - if (position - 1 == -1) { - return false; - } - final Comment item = mAdapter.getItem(position - 1); - if (item == null) - return false; - int itemsLen = item.getAuthorId() == AppContext.getInstance() - .getLoginUid() ? 2 : 1; - String[] items = new String[itemsLen]; - items[0] = getResources().getString(R.string.copy); - if (itemsLen == 2) { - items[1] = getResources().getString(R.string.delete); - } - DialogHelp.getSelectDialog(getActivity(), items, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (i == 0) { - TDevice.copyTextToBoard(HTMLUtil.delHTMLTag(item - .getContent())); - } else if (i == 1) { - handleDeleteComment(item); - } - } - }).show(); - return true; - } - - @Override - protected void requestDetailData(boolean isRefresh) { - String key = getDetailCacheKey(); - mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING); - if (TDevice.hasInternet() - && (!CacheManager.isExistDataCache(getActivity(), key) || isRefresh)) { - OSChinaApi.getTweetDetail(mTweetId, mDetailHandler); - } else { - readDetailCacheData(key); - } - } - - @Override - protected boolean isRefresh() { - return true; - } - - @Override - protected View initHeaderView() { - Intent args = getActivity().getIntent(); - mTweetId = args.getIntExtra("tweet_id", 0); - mTweet = (Tweet) args.getParcelableExtra("tweet"); - - mListView.setOnItemLongClickListener(this); - View header = LayoutInflater.from(getActivity()).inflate( - R.layout.list_header_tweet_detail, null); - mIvAvatar = (AvatarView) header.findViewById(R.id.iv_avatar); - - mTvName = (TextView) header.findViewById(R.id.tv_name); - mTvFrom = (TextView) header.findViewById(R.id.tv_from); - mTvTime = (TextView) header.findViewById(R.id.tv_time); - mTvCommentCount = (TextView) header.findViewById(R.id.tv_comment_count); - mContent = (WebView) header.findViewById(R.id.webview); - UIHelper.initWebView(mContent); - mContent.loadUrl("file:///android_asset/detail_page.html"); - initSoundView(header); - mLikeUser = (TextView) header.findViewById(R.id.tv_likeusers); - mTvLikeState = (TextView) header.findViewById(R.id.tv_like_state); - mTvLikeState.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - likeOption(); - } - }); - TypefaceUtils.setTypeface(mTvLikeState); - return header; - } - - private void likeOption() { - if (mTweet == null) - return; - AsyncHttpResponseHandler handler = new AsyncHttpResponseHandler() { - - @Override - public void onSuccess(int arg0, Header[] arg1, byte[] arg2) {} - - @Override - public void onFailure(int arg0, Header[] arg1, byte[] arg2, - Throwable arg3) {} - }; - if (AppContext.getInstance().isLogin()) { - if (mTweet.getIsLike() == 1) { - mTweet.setIsLike(0); - mTweet.getLikeUser().remove(0); - mTweet.setLikeCount(mTweet.getLikeCount() - 1); - OSChinaApi.pubUnLikeTweet(mTweetId, mTweet.getAuthorid(), - handler); - } else { - mTvLikeState.setAnimation(KJAnimations.getScaleAnimation(1.5f, - 300)); - mTweet.setIsLike(1); - mTweet.getLikeUser().add(0, - AppContext.getInstance().getLoginUser()); - mTweet.setLikeCount(mTweet.getLikeCount() + 1); - OSChinaApi - .pubLikeTweet(mTweetId, mTweet.getAuthorid(), handler); - } - setLikeState(); - mTweet.setLikeUsers(getActivity(), mLikeUser, false); - } else { - AppContext.showToast("先登陆再点赞~"); - UIHelper.showLoginActivity(getActivity()); - } - } - - @Override - protected String getDetailCacheKey() { - return CACHE_KEY_PREFIX + mTweetId; - } - - @Override - protected void executeOnLoadDetailSuccess(TweetDetail detailBean) { - mErrorLayout.setErrorType(EmptyLayout.HIDE_LAYOUT); - this.mTweet = detailBean.getTweet(); - fillUI(); - mAdapter.setNoDataText(R.string.comment_empty); - } - - @Override - protected TweetDetail getDetailBean(ByteArrayInputStream is) { - return XmlUtils.toBean(TweetDetail.class, is); - } - - @Override - protected void executeOnLoadDataSuccess(List data) { - super.executeOnLoadDataSuccess(data); - int commentCount = StringUtils.toInt(mTweet == null ? 0 : this.mTweet - .getCommentCount()); - if (commentCount < (mAdapter.getCount() - 1)) { - commentCount = mAdapter.getCount() - 1; - } - mTvCommentCount.setText(commentCount + ""); - } - - @Override - public void onClickSendButton(Editable str) { - if (!AppContext.getInstance().isLogin()) { - UIHelper.showLoginActivity(getActivity()); - return; - } - if (!TDevice.hasInternet()) { - AppContext.showToastShort(R.string.tip_network_error); - return; - } - if (TextUtils.isEmpty(str)) { - AppContext.showToastShort(R.string.tip_comment_content_empty); - return; - } - showWaitDialog(R.string.progress_submit); - try { - if (outAty.emojiFragment.getEditText().getTag() != null) { - Comment comment = (Comment) outAty.emojiFragment.getEditText() - .getTag(); - OSChinaApi.replyComment(mTweetId, CommentList.CATALOG_TWEET, - comment.getId(), comment.getAuthorId(), AppContext - .getInstance().getLoginUid(), str.toString(), - mCommentHandler); - } else { - OSChinaApi.publicComment(CommentList.CATALOG_TWEET, mTweetId, - AppContext.getInstance().getLoginUid(), str.toString(), - 0, mCommentHandler); - } - } catch (Exception e) { - } - } - - @Override - public void onClickFlagButton() {} - - @Override - public boolean onBackPressed() { - if (outAty.emojiFragment.isShowEmojiKeyBoard()) { - outAty.emojiFragment.hideAllKeyBoard(); - return true; - } - if (outAty.emojiFragment.getEditText().getTag() != null) { - outAty.emojiFragment.getEditText().setTag(null); - outAty.emojiFragment.getEditText().setHint("说点什么吧"); - return true; - } - return super.onBackPressed(); - } -} diff --git a/app/src/main/java/net/oschina/app/fragment/TweetLikeUsersFragment.java b/app/src/main/java/net/oschina/app/fragment/TweetLikeUsersFragment.java deleted file mode 100644 index 8ece7df02377853f9d4cb2163d2743427c16ef5f..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/fragment/TweetLikeUsersFragment.java +++ /dev/null @@ -1,77 +0,0 @@ -package net.oschina.app.fragment; - -import java.io.InputStream; -import java.io.Serializable; - -import android.os.Bundle; -import android.view.View; -import android.widget.AdapterView; - -import net.oschina.app.adapter.TweetLikeUsersAdapter; -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.base.BaseActivity; -import net.oschina.app.base.BaseListFragment; -import net.oschina.app.bean.TweetLikeUserList; -import net.oschina.app.bean.User; -import net.oschina.app.util.UIHelper; -import net.oschina.app.util.XmlUtils; - -/** - * TweetLikeUsersFragment.java - * - * @author 火蚁(http://my.oschina.net/u/253900) - * - * @data 2015-3-26 下午4:04:12 - */ -public class TweetLikeUsersFragment extends BaseListFragment { - - @Override - protected TweetLikeUsersAdapter getListAdapter() { - // TODO Auto-generated method stub - return new TweetLikeUsersAdapter(); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - // TODO Auto-generated method stub - super.onCreate(savedInstanceState); - BaseActivity activity = (BaseActivity) getActivity(); - activity.setActionBarTitle("动弹点赞列表"); - } - - @Override - protected String getCacheKeyPrefix() { - // TODO Auto-generated method stub - return "tweet_like_list_" + mCatalog; - } - - @Override - protected TweetLikeUserList parseList(InputStream is) throws Exception { - // TODO Auto-generated method stub - TweetLikeUserList list = XmlUtils.toBean(TweetLikeUserList.class, is); - return list; - } - - @Override - protected TweetLikeUserList readList(Serializable seri) { - // TODO Auto-generated method stub - return (TweetLikeUserList) seri; - } - - @Override - protected void sendRequestData() { - // TODO Auto-generated method stub - OSChinaApi.getTweetLikeList(mCatalog, mCurrentPage, mHandler); - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, - long id) { - // TODO Auto-generated method stub - User item = mAdapter.getItem(position); - if (item != null && item.getId() > 0) { - UIHelper.showUserCenter(getActivity(), item.getId(), item.getName()); - } - } -} - diff --git a/app/src/main/java/net/oschina/app/fragment/TweetPubFragment.java b/app/src/main/java/net/oschina/app/fragment/TweetPubFragment.java deleted file mode 100644 index 54a2d751c9dbd70f62af9eaf8bbfbe669e4a7b52..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/fragment/TweetPubFragment.java +++ /dev/null @@ -1,687 +0,0 @@ -package net.oschina.app.fragment; - -import android.app.Activity; -import android.content.DialogInterface; -import android.content.Intent; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.os.Environment; -import android.os.Handler; -import android.os.Message; -import android.provider.MediaStore; -import android.provider.MediaStore.Images; -import android.support.annotation.Nullable; -import android.text.TextUtils; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.view.WindowManager; -import android.widget.EditText; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.TextView; - -import net.oschina.app.AppContext; -import net.oschina.app.R; -import net.oschina.app.base.BaseFragment; -import net.oschina.app.bean.Tweet; -import net.oschina.app.emoji.EmojiKeyboardFragment; -import net.oschina.app.emoji.Emojicon; -import net.oschina.app.emoji.InputHelper; -import net.oschina.app.emoji.OnEmojiClickListener; -import net.oschina.app.service.ServerTaskUtils; -import net.oschina.app.ui.SelectFriendsActivity; -import net.oschina.app.util.DialogHelp; -import net.oschina.app.util.FileUtil; -import net.oschina.app.util.ImageUtils; -import net.oschina.app.util.SimpleTextWatcher; -import net.oschina.app.util.StringUtils; -import net.oschina.app.util.TDevice; -import net.oschina.app.util.UIHelper; - -import org.kymjs.kjframe.Core; -import org.kymjs.kjframe.bitmap.BitmapCallBack; -import org.kymjs.kjframe.bitmap.BitmapCreate; -import org.kymjs.kjframe.bitmap.DiskImageRequest; -import org.kymjs.kjframe.http.KJAsyncTask; -import org.kymjs.kjframe.utils.FileUtils; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.text.SimpleDateFormat; -import java.util.Date; - -import butterknife.ButterKnife; -import butterknife.InjectView; - -public class TweetPubFragment extends BaseFragment implements - OnEmojiClickListener { - - public static final int ACTION_TYPE_ALBUM = 0; - public static final int ACTION_TYPE_PHOTO = 1; - public static final int ACTION_TYPE_RECORD = 2; // 录音 - public static final int ACTION_TYPE_TOPIC = 3; // 录音 - public static final String FROM_IMAGEPAGE_KEY = "from_image_page"; - - public static final String ACTION_TYPE = "action_type"; - - private static final int MAX_TEXT_LENGTH = 160; - private static final String TEXT_ATME = "@请输入用户名 "; - private static final String TEXT_SOFTWARE = "#请输入软件名#"; - - private static final int SELECT_FRIENDS_REEQUEST_CODE = 100; - - private String fromSharedTextContent = ""; - - @InjectView(R.id.ib_emoji_keyboard) - ImageButton mIbEmoji; - - @InjectView(R.id.ib_picture) - ImageButton mIbPicture; - - @InjectView(R.id.ib_mention) - ImageButton mIbMention; - - @InjectView(R.id.ib_trend_software) - ImageButton mIbTrendSoftware; - - @InjectView(R.id.tv_clear) - TextView mTvClear; - - @InjectView(R.id.rl_img) - View mLyImage; - - @InjectView(R.id.iv_img) - ImageView mIvImage; - - @InjectView(R.id.et_content) - EditText mEtInput; - - private MenuItem mSendMenu; - - private boolean mIsKeyboardVisible; - - private final EmojiKeyboardFragment keyboardFragment = new EmojiKeyboardFragment(); - - private String theLarge, theThumbnail; - private File imgFile; - - private final Handler handler = new Handler() { - @Override - public void handleMessage(Message msg) { - if (msg.what == 1 && msg.obj != null) { - // 显示图片 - mIvImage.setImageBitmap((Bitmap) msg.obj); - mLyImage.setVisibility(View.VISIBLE); - } - } - }; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - int mode = WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE - | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; - getActivity().getWindow().setSoftInputMode(mode); - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - super.onCreateOptionsMenu(menu, inflater); - inflater.inflate(R.menu.pub_topic_menu, menu); - mSendMenu = menu.findItem(R.id.public_menu_send); - updateMenuState(); - } - - public void updateMenuState() { - if (mSendMenu == null) { - return; - } - if (mEtInput.getText().length() == 0) { - mSendMenu.setEnabled(false); - mSendMenu.setIcon(R.drawable.actionbar_unsend_icon); - } else { - mSendMenu.setEnabled(true); - mSendMenu.setIcon(R.drawable.actionbar_send_icon); - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.public_menu_send: - handleSubmit(); - break; - default: - break; - } - return true; - } - - /** - * 方便外部Activity调用 - */ - public void setContentText(String content) { - fromSharedTextContent = content; - if (mEtInput != null) { - mEtInput.setText(content); - } - } - - /** - * 方便外部Activity调用 - */ - public void setContentImage(String url) { - handleImageFile(url); - } - - private void handleSubmit() { - if (!TDevice.hasInternet()) { - AppContext.showToastShort(R.string.tip_network_error); - return; - } - if (!AppContext.getInstance().isLogin()) { - UIHelper.showLoginActivity(getActivity()); - return; - } - String content = mEtInput.getText().toString().trim(); - if (TextUtils.isEmpty(content)) { - mEtInput.requestFocus(); - AppContext.showToastShort(R.string.tip_content_empty); - return; - } - if (content.length() > MAX_TEXT_LENGTH) { - AppContext.showToastShort(R.string.tip_content_too_long); - return; - } - - Tweet tweet = new Tweet(); - tweet.setAuthorid(AppContext.getInstance().getLoginUid()); - tweet.setBody(content); - if (imgFile != null && imgFile.exists()) { - tweet.setImageFilePath(imgFile.getAbsolutePath()); - } - ServerTaskUtils.pubTweet(getActivity(), tweet); - if (mIsKeyboardVisible) { - TDevice.hideSoftKeyboard(getActivity().getCurrentFocus()); - } - getActivity().finish(); - } - - @Override - public View onCreateView(LayoutInflater inflater, - @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_tweet_pub, container, - false); - - initView(view); - return view; - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - Bundle bundle = getArguments(); - if (bundle != null) { - int action_type = bundle.getInt(ACTION_TYPE, -1); - goToSelectPicture(action_type); - final String imgUrl = bundle.getString(FROM_IMAGEPAGE_KEY); - handleImageUrl(imgUrl); - } - } - - /** - * 处理从第三方分享跳转来的图片 - * - * @param filePath - */ - private void handleImageFile(final String filePath) { - if (!StringUtils.isEmpty(filePath)) { - KJAsyncTask.execute(new Runnable() { - @Override - public void run() { - final Message msg = Message.obtain(); - msg.what = 1; - try { - msg.obj = BitmapCreate.bitmapFromStream( - new FileInputStream(filePath), 300, 300); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } - String path = FileUtils.getSDCardPath() - + "/OSChina/tempfile.jpg"; - FileUtils.bitmapToFile((Bitmap) msg.obj, path); - imgFile = new File(path); - handler.sendMessage(msg); - } - }); - } - } - - /** - * 处理从图片浏览跳转来的图片 - * - * @param url - */ - private void handleImageUrl(final String url) { - if (!StringUtils.isEmpty(url)) { - final Message msg = Message.obtain(); - msg.what = 1; - byte[] cache = Core.getKJBitmap().getCache(url); - msg.obj = BitmapFactory.decodeByteArray(cache, 0, cache.length); - if (msg.obj == null) { - DiskImageRequest req = new DiskImageRequest(); - req.load(url, 300, 300, new BitmapCallBack() { - @Override - public void onSuccess(Bitmap bitmap) { - super.onSuccess(bitmap); - msg.obj = bitmap; - String path = FileUtils.getSDCardPath() - + "/OSChina/tempfile.jpg"; - handler.sendMessage(msg); - FileUtils.bitmapToFile((Bitmap) msg.obj, path); - imgFile = new File(path); - } - }); - } else { - String path = FileUtils.getSDCardPath() - + "/OSChina/tempfile.jpg"; - FileUtils.bitmapToFile((Bitmap) msg.obj, path); - imgFile = new File(path); - handler.sendMessage(msg); - } - } - } - - @Override - public void initView(View view) { - super.initView(view); - ButterKnife.inject(this, view); - setHasOptionsMenu(true); - mIbEmoji.setOnClickListener(this); - mIbPicture.setOnClickListener(this); - mIbMention.setOnClickListener(this); - mIbTrendSoftware.setOnClickListener(this); - mTvClear.setOnClickListener(this); - mTvClear.setText(String.valueOf(MAX_TEXT_LENGTH)); - view.findViewById(R.id.iv_clear_img).setOnClickListener(this); - - mEtInput.addTextChangedListener(new SimpleTextWatcher() { - @Override - public void onTextChanged(CharSequence s, int start, int before, - int count) { - mTvClear.setText((MAX_TEXT_LENGTH - s.length()) + ""); - updateMenuState(); - } - }); - // 获取保存的tweet草稿 - mEtInput.setText(AppContext.getTweetDraft()); - mEtInput.setSelection(mEtInput.getText().toString().length()); - - mEtInput.addTextChangedListener(new SimpleTextWatcher() { - @Override - public void onTextChanged(CharSequence s, int start, int before, - int count) { - mTvClear.setText((MAX_TEXT_LENGTH - s.length()) + ""); - } - }); - // 获取保存的tweet草稿 - String content = fromSharedTextContent; - if (StringUtils.isEmpty(fromSharedTextContent)) { - content = AppContext.getTweetDraft(); - } - mEtInput.setText(content); - mEtInput.setSelection(mEtInput.getText().toString().length()); - - getFragmentManager().beginTransaction() - .replace(R.id.emoji_keyboard_fragment, keyboardFragment) - .commit(); - keyboardFragment.setOnEmojiClickListener(new OnEmojiClickListener() { - @Override - public void onEmojiClick(Emojicon v) { - InputHelper.input2OSC(mEtInput, v); - } - - @Override - public void onDeleteButtonClick(View v) { - InputHelper.backspace(mEtInput); - } - }); - } - - @Override - public boolean onBackPressed() { - final String tweet = mEtInput.getText().toString(); - if (!TextUtils.isEmpty(tweet)) { - DialogHelp.getConfirmDialog(getActivity(), "是否保存为草稿?", new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - AppContext.setTweetDraft(tweet); - getActivity().finish(); - } - }, new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - AppContext.setTweetDraft(""); - getActivity().finish(); - } - }).show(); - return true; - } - return super.onBackPressed(); - } - - @Override - public void onClick(View v) { - final int id = v.getId(); - if (id == R.id.ib_picture) { - handleSelectPicture(); - } else if (id == R.id.ib_mention) { - //insertMention(); - handleSelectFriends(); - } else if (id == R.id.ib_trend_software) { - insertTrendSoftware(); - } else if (id == R.id.tv_clear) { - handleClearWords(); - } else if (id == R.id.iv_clear_img) { - mIvImage.setImageBitmap(null); - mLyImage.setVisibility(View.GONE); - imgFile = null; - } else if (id == R.id.ib_emoji_keyboard) { - if (!keyboardFragment.isShow()) {// emoji隐藏中 - keyboardFragment.showEmojiKeyBoard(); - keyboardFragment.hideSoftKeyboard(); - } else { - keyboardFragment.hideEmojiKeyBoard(); - keyboardFragment.showSoftKeyboard(mEtInput); - } - } - } - - @Override - public void onActivityResult(final int requestCode, final int resultCode, - final Intent imageReturnIntent) { - if (resultCode != Activity.RESULT_OK) - return; - if(requestCode == SELECT_FRIENDS_REEQUEST_CODE) { - //选中好友的名字 - String names[] = imageReturnIntent.getStringArrayExtra("names"); - if(names != null && names.length > 0) { - //拼成字符串 - String text = ""; - for(String n : names) { - text += "@" + n + " "; - } - //插入到文本中 - mEtInput.getText().insert(mEtInput.getSelectionStart(), text); - } - return; - } - new Thread() { - private String selectedImagePath; - - @Override - public void run() { - Bitmap bitmap = null; - - if (requestCode == ImageUtils.REQUEST_CODE_GETIMAGE_BYSDCARD) { - if (imageReturnIntent == null) - return; - Uri selectedImageUri = imageReturnIntent.getData(); - if (selectedImageUri != null) { - selectedImagePath = ImageUtils.getImagePath( - selectedImageUri, getActivity()); - } - - if (selectedImagePath != null) { - theLarge = selectedImagePath; - } else { - bitmap = ImageUtils.loadPicasaImageFromGalley( - selectedImageUri, getActivity()); - } - - if (AppContext - .isMethodsCompat(android.os.Build.VERSION_CODES.ECLAIR_MR1)) { - String imaName = FileUtil.getFileName(theLarge); - if (imaName != null) - bitmap = ImageUtils.loadImgThumbnail(getActivity(), - imaName, - MediaStore.Images.Thumbnails.MICRO_KIND); - } - if (bitmap == null && !StringUtils.isEmpty(theLarge)) - bitmap = ImageUtils - .loadImgThumbnail(theLarge, 100, 100); - } else if (requestCode == ImageUtils.REQUEST_CODE_GETIMAGE_BYCAMERA) { - // 拍摄图片 - if (bitmap == null && !StringUtils.isEmpty(theLarge)) { - bitmap = ImageUtils - .loadImgThumbnail(theLarge, 100, 100); - } - } - - if (bitmap != null) {// 存放照片的文件夹 - String savePath = Environment.getExternalStorageDirectory() - .getAbsolutePath() + "/OSChina/Camera/"; - File savedir = new File(savePath); - if (!savedir.exists()) { - savedir.mkdirs(); - } - - String largeFileName = FileUtil.getFileName(theLarge); - String largeFilePath = savePath + largeFileName; - // 判断是否已存在缩略图 - if (largeFileName.startsWith("thumb_") - && new File(largeFilePath).exists()) { - theThumbnail = largeFilePath; - imgFile = new File(theThumbnail); - } else { - // 生成上传的800宽度图片 - String thumbFileName = "thumb_" + largeFileName; - theThumbnail = savePath + thumbFileName; - if (new File(theThumbnail).exists()) { - imgFile = new File(theThumbnail); - } else { - try { - // 压缩上传的图片 - ImageUtils.createImageThumbnail(getActivity(), - theLarge, theThumbnail, 800, 80); - imgFile = new File(theThumbnail); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - // 保存动弹临时图片 - // ((AppContext) getApplication()).setProperty( - // tempTweetImageKey, theThumbnail); - - Message msg = new Message(); - msg.what = 1; - msg.obj = bitmap; - handler.sendMessage(msg); - } - }; - }.start(); - } - - private void handleClearWords() { - if (TextUtils.isEmpty(mEtInput.getText().toString())) - return; - DialogHelp.getConfirmDialog(getActivity(), "是否清空内容?", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - mEtInput.getText().clear(); - if (mIsKeyboardVisible) { - TDevice.showSoftKeyboard(mEtInput); - } - } - }).show(); - } - - @Override - public void onResume() { - super.onResume(); - keyboardFragment.showSoftKeyboard(mEtInput); - keyboardFragment.hideEmojiKeyBoard(); - } - - /** 跳转选择好友*/ - private void handleSelectFriends() { - //如果没登录,则先去登录界面 - if (!AppContext.getInstance().isLogin()) { - UIHelper.showLoginActivity(getActivity()); - return; - } - Intent intent = new Intent(getActivity(), SelectFriendsActivity.class); - startActivityForResult(intent, SELECT_FRIENDS_REEQUEST_CODE); - } - - private void handleSelectPicture() { - DialogHelp.getSelectDialog(getActivity(), getResources().getStringArray(R.array.choose_picture), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - goToSelectPicture(i); - } - }).show(); - } - - private void goToSelectPicture(int position) { - switch (position) { - case ACTION_TYPE_ALBUM: - Intent intent; - if (Build.VERSION.SDK_INT < 19) { - intent = new Intent(); - intent.setAction(Intent.ACTION_GET_CONTENT); - intent.setType("image/*"); - startActivityForResult(Intent.createChooser(intent, "选择图片"), - ImageUtils.REQUEST_CODE_GETIMAGE_BYSDCARD); - } else { - intent = new Intent(Intent.ACTION_PICK, - Images.Media.EXTERNAL_CONTENT_URI); - intent.setType("image/*"); - startActivityForResult(Intent.createChooser(intent, "选择图片"), - ImageUtils.REQUEST_CODE_GETIMAGE_BYSDCARD); - } - break; - case ACTION_TYPE_PHOTO: - // 判断是否挂载了SD卡 - String savePath = ""; - String storageState = Environment.getExternalStorageState(); - if (storageState.equals(Environment.MEDIA_MOUNTED)) { - savePath = Environment.getExternalStorageDirectory() - .getAbsolutePath() + "/oschina/Camera/"; - File savedir = new File(savePath); - if (!savedir.exists()) { - savedir.mkdirs(); - } - } - - // 没有挂载SD卡,无法保存文件 - if (StringUtils.isEmpty(savePath)) { - AppContext.showToastShort("无法保存照片,请检查SD卡是否挂载"); - return; - } - - String timeStamp = new SimpleDateFormat("yyyyMMddHHmmss") - .format(new Date()); - String fileName = "osc_" + timeStamp + ".jpg";// 照片命名 - File out = new File(savePath, fileName); - Uri uri = Uri.fromFile(out); - - theLarge = savePath + fileName;// 该照片的绝对路径 - - intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); - intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); - startActivityForResult(intent, - ImageUtils.REQUEST_CODE_GETIMAGE_BYCAMERA); - break; - case ACTION_TYPE_TOPIC: - Bundle bundle = getArguments(); - if (bundle != null) { - String topic = bundle.getString("tweet_topic"); - setContentText(topic); - if (mEtInput != null) { - mEtInput.setSelection(topic.length()); - } - } - break; - default: - break; - } - } - - private void insertMention() { - TDevice.showSoftKeyboard(mEtInput); - // 在光标所在处插入“@用户名” - int curTextLength = mEtInput.getText().length(); - if (curTextLength >= MAX_TEXT_LENGTH) - return; - String atme = TEXT_ATME; - int start, end; - if ((MAX_TEXT_LENGTH - curTextLength) >= atme.length()) { - start = mEtInput.getSelectionStart() + 1; - end = start + atme.length() - 2; - } else { - int num = MAX_TEXT_LENGTH - curTextLength; - if (num < atme.length()) { - atme = atme.substring(0, num); - } - start = mEtInput.getSelectionStart() + 1; - end = start + atme.length() - 1; - } - if (start > MAX_TEXT_LENGTH || end > MAX_TEXT_LENGTH) { - start = MAX_TEXT_LENGTH; - end = MAX_TEXT_LENGTH; - } - mEtInput.getText().insert(mEtInput.getSelectionStart(), atme); - mEtInput.setSelection(start, end);// 设置选中文字 - } - - private void insertTrendSoftware() { - // 在光标所在处插入“#软件名#” - int curTextLength = mEtInput.getText().length(); - if (curTextLength >= MAX_TEXT_LENGTH) - return; - String software = TEXT_SOFTWARE; - int start, end; - if ((MAX_TEXT_LENGTH - curTextLength) >= software.length()) { - start = mEtInput.getSelectionStart() + 1; - end = start + software.length() - 2; - } else { - int num = MAX_TEXT_LENGTH - curTextLength; - if (num < software.length()) { - software = software.substring(0, num); - } - start = mEtInput.getSelectionStart() + 1; - end = start + software.length() - 1; - } - if (start > MAX_TEXT_LENGTH || end > MAX_TEXT_LENGTH) { - start = MAX_TEXT_LENGTH; - end = MAX_TEXT_LENGTH; - } - mEtInput.getText().insert(mEtInput.getSelectionStart(), software); - mEtInput.setSelection(start, end);// 设置选中文字 - } - - @Override - public void initData() {} - - @Override - public void onDeleteButtonClick(View v) {} - - @Override - public void onEmojiClick(Emojicon v) { - InputHelper.input2OSC(mEtInput, v); - } -} diff --git a/app/src/main/java/net/oschina/app/fragment/TweetRecordFragment.java b/app/src/main/java/net/oschina/app/fragment/TweetRecordFragment.java deleted file mode 100644 index a7b3b5eae7969e299a433407e17ef8d41939a6e8..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/fragment/TweetRecordFragment.java +++ /dev/null @@ -1,213 +0,0 @@ -package net.oschina.app.fragment; - -import java.io.File; - -import net.oschina.app.AppContext; -import net.oschina.app.R; -import net.oschina.app.base.BaseFragment; -import net.oschina.app.bean.Tweet; -import net.oschina.app.service.ServerTaskUtils; -import net.oschina.app.util.StringUtils; -import net.oschina.app.util.TDevice; -import net.oschina.app.util.UIHelper; -import net.oschina.app.widget.RecordButton; -import net.oschina.app.widget.RecordButton.OnFinishedRecordListener; -import net.oschina.app.widget.RecordButtonUtil.OnPlayListener; - -import org.kymjs.kjframe.utils.DensityUtils; - -import android.graphics.drawable.AnimationDrawable; -import android.os.Bundle; -import android.text.Editable; -import android.text.Selection; -import android.text.Spannable; -import android.text.TextWatcher; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.EditText; -import android.widget.ImageView; -import android.widget.RelativeLayout; -import android.widget.RelativeLayout.LayoutParams; -import android.widget.TextView; -import butterknife.ButterKnife; -import butterknife.InjectView; - -/** - * 语音动弹发布界面 - * - * @author kymjs(kymjs123@gmail.com) - * - */ -public class TweetRecordFragment extends BaseFragment { - - @InjectView(R.id.tweet_layout_record) - RelativeLayout mLayout; - @InjectView(R.id.tweet_btn_record) - RecordButton mBtnRecort; - @InjectView(R.id.tweet_time_record) - TextView mTvTime; - @InjectView(R.id.tweet_text_record) - TextView mTvInputLen; - @InjectView(R.id.tweet_edit_record) - EditText mEtSpeech; - @InjectView(R.id.tweet_img_volume) - ImageView mImgVolume; - - public static int MAX_LEN = 160; - - private AnimationDrawable drawable; // 录音播放时的动画背景 - - private String strSpeech = "#语音动弹#"; - private int currentRecordTime = 0; - - @Override - public void onClick(View v) { - if (v == mLayout) { - mBtnRecort.playRecord(); - } - } - - @Override - public void initView(View view) { - RelativeLayout.LayoutParams params = (LayoutParams) mBtnRecort - .getLayoutParams(); - params.width = DensityUtils.getScreenW(getActivity()); - params.height = (int) (DensityUtils.getScreenH(getActivity()) * 0.4); - mBtnRecort.setLayoutParams(params); - mLayout.setOnClickListener(this); - - mBtnRecort.setOnFinishedRecordListener(new OnFinishedRecordListener() { - @Override - public void onFinishedRecord(String audioPath, int recordTime) { - currentRecordTime = recordTime; - mLayout.setVisibility(View.VISIBLE); - if (recordTime < 10) { - mTvTime.setText("0" + recordTime + "\""); - } else { - mTvTime.setText(recordTime + "\""); - } - } - - @Override - public void onCancleRecord() { - mLayout.setVisibility(View.GONE); - } - }); - - drawable = (AnimationDrawable) mImgVolume.getBackground(); - mBtnRecort.getAudioUtil().setOnPlayListener(new OnPlayListener() { - @Override - public void stopPlay() { - drawable.stop(); - mImgVolume.setBackgroundDrawable(drawable.getFrame(0)); - } - - @Override - public void starPlay() { - mImgVolume.setBackgroundDrawable(drawable); - drawable.start(); - } - }); - - mEtSpeech.addTextChangedListener(new TextWatcher() { - @Override - public void onTextChanged(CharSequence s, int start, int before, - int count) { - if (s.length() > MAX_LEN) { - mTvInputLen.setText("已达到最大长度"); - } else { - mTvInputLen.setText("您还可以输入" + (MAX_LEN - s.length()) - + "个字符"); - } - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, - int after) {} - - @Override - public void afterTextChanged(Editable s) { - if (s.length() > MAX_LEN) { - mEtSpeech.setText(s.subSequence(0, MAX_LEN)); - CharSequence text = mEtSpeech.getText(); - if (text instanceof Spannable) - Selection.setSelection((Spannable) text, MAX_LEN); - } - } - }); - } - - @Override - public void initData() {} - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - super.onCreateView(inflater, container, savedInstanceState); - View rootView = inflater.inflate(R.layout.item_tweet_pub_record, - container, false); - ButterKnife.inject(this, rootView); - initView(rootView); - initData(); - return rootView; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setHasOptionsMenu(true); - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - inflater.inflate(R.menu.pub_tweet_menu, menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.public_menu_send: - handleSubmit(mBtnRecort.getCurrentAudioPath()); - break; - } - return true; - } - - /** - * 发布动弹 - */ - private void handleSubmit(String audioPath) { - if (!TDevice.hasInternet()) { - AppContext.showToastShort(R.string.tip_network_error); - return; - } - if (!AppContext.getInstance().isLogin()) { - UIHelper.showLoginActivity(getActivity()); - return; - } - if (StringUtils.isEmpty(audioPath)) { - AppContext.showToastShort(R.string.record_sound_notfound); - return; - } - File file = new File(audioPath); - if (!file.exists()) { - AppContext.showToastShort(R.string.record_sound_notfound); - return; - } - - String body = mEtSpeech.getText().toString(); - if (!StringUtils.isEmpty(body)) { - strSpeech = body; - } - Tweet tweet = new Tweet(); - tweet.setAuthorid(AppContext.getInstance().getLoginUid()); - tweet.setAudioPath(audioPath); - tweet.setBody(strSpeech); - ServerTaskUtils.pubTweet(getActivity(), tweet); - getActivity().finish(); - } -} diff --git a/app/src/main/java/net/oschina/app/fragment/TweetsFragment.java b/app/src/main/java/net/oschina/app/fragment/TweetsFragment.java deleted file mode 100644 index d384666ca97597aedad4fb349a25b7a32d8013d1..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/fragment/TweetsFragment.java +++ /dev/null @@ -1,273 +0,0 @@ -package net.oschina.app.fragment; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Bundle; -import android.view.View; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemLongClickListener; -import cz.msebera.android.httpclient.Header; - -import net.oschina.app.AppContext; -import net.oschina.app.R; -import net.oschina.app.adapter.TweetAdapter; -import net.oschina.app.api.OperationResponseHandler; -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.base.BaseListFragment; -import net.oschina.app.bean.Constants; -import net.oschina.app.bean.Result; -import net.oschina.app.bean.ResultBean; -import net.oschina.app.bean.Tweet; -import net.oschina.app.bean.TweetsList; -import net.oschina.app.interf.OnTabReselectListener; -import net.oschina.app.ui.empty.EmptyLayout; -import net.oschina.app.util.DialogHelp; -import net.oschina.app.util.HTMLUtil; -import net.oschina.app.util.TDevice; -import net.oschina.app.util.UIHelper; -import net.oschina.app.util.XmlUtils; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.io.Serializable; - -/** - * @author kymjs (http://www.kymjs.com) - */ -public class TweetsFragment extends BaseListFragment implements - OnItemLongClickListener, OnTabReselectListener { - - protected static final String TAG = TweetsFragment.class.getSimpleName(); - private static final String CACHE_KEY_PREFIX = "tweetslist_"; - - class DeleteTweetResponseHandler extends OperationResponseHandler { - - DeleteTweetResponseHandler(Object... args) { - super(args); - } - - @Override - public void onSuccess(int code, ByteArrayInputStream is, Object[] args) - throws Exception { - try { - Result res = XmlUtils.toBean(ResultBean.class, is).getResult(); - if (res != null && res.OK()) { - AppContext.showToastShort(R.string.delete_success); - Tweet tweet = (Tweet) args[0]; - mAdapter.removeItem(tweet); - mAdapter.notifyDataSetChanged(); - } else { - onFailure(code, res.getErrorMessage(), args); - } - } catch (Exception e) { - e.printStackTrace(); - onFailure(code, e.getMessage(), args); - } - } - - @Override - public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { - - } - - @Override - public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { - AppContext.showToastShort(R.string.delete_faile); - } - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (mCatalog > 0) { - IntentFilter filter = new IntentFilter( - Constants.INTENT_ACTION_USER_CHANGE); - filter.addAction(Constants.INTENT_ACTION_LOGOUT); - getActivity().registerReceiver(mReceiver, filter); - } - } - - @Override - public void onDestroy() { - if (mCatalog > 0) { - getActivity().unregisterReceiver(mReceiver); - } - super.onDestroy(); - } - - @Override - protected TweetAdapter getListAdapter() { - return new TweetAdapter(); - } - - @Override - protected String getCacheKeyPrefix() { - Bundle bundle = getArguments(); - if (bundle != null) { - String str = bundle.getString("topic"); - if (str != null) { - return str; - } - } - return CACHE_KEY_PREFIX + mCatalog; - } - - public String getTopic() { - Bundle bundle = getArguments(); - if (bundle != null) { - String str = bundle.getString("topic"); - if (str != null) { - return str; - } - } - return ""; - } - - @Override - protected TweetsList parseList(InputStream is) throws Exception { - TweetsList list = XmlUtils.toBean(TweetsList.class, is); - return list; - } - - @Override - protected TweetsList readList(Serializable seri) { - return ((TweetsList) seri); - } - - @Override - protected void sendRequestData() { - Bundle bundle = getArguments(); - if (bundle != null) { - String str = bundle.getString("topic"); - if (str != null) { - OSChinaApi.getTweetTopicList(mCurrentPage, str, mHandler); - return; - } - } - OSChinaApi.getTweetList(mCatalog, mCurrentPage, mHandler); - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, - long id) { - Tweet tweet = mAdapter.getItem(position); - if (tweet != null) { - UIHelper.showTweetDetail(view.getContext(), null, tweet.getId()); - } - } - - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - setupContent(); - } - }; - - private void setupContent() { - if (AppContext.getInstance().isLogin()) { - mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING); - requestData(true); - } else { - mCatalog = TweetsList.CATALOG_ME; - mErrorLayout.setErrorType(EmptyLayout.NETWORK_ERROR); - mErrorLayout.setErrorMessage(getString(R.string.unlogin_tip)); - } - } - - @Override - protected void requestData(boolean refresh) { - if (mCatalog > 0) { - if (AppContext.getInstance().isLogin()) { - mCatalog = AppContext.getInstance().getLoginUid(); - super.requestData(refresh); - } else { - mErrorLayout.setErrorType(EmptyLayout.NETWORK_ERROR); - mErrorLayout.setErrorMessage(getString(R.string.unlogin_tip)); - } - } else { - super.requestData(refresh); - } - } - - @Override - public void initView(View view) { - super.initView(view); - mListView.setOnItemLongClickListener(this); - mErrorLayout.setOnLayoutClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - if (mCatalog > 0) { - if (AppContext.getInstance().isLogin()) { - mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING); - requestData(true); - } else { - UIHelper.showLoginActivity(getActivity()); - } - } else { - mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING); - requestData(true); - } - } - }); - } - - @Override - public boolean onItemLongClick(AdapterView parent, View view, - int position, long id) { - Tweet tweet = mAdapter.getItem(position); - if (tweet != null) { - handleLongClick(tweet); - return true; - } - return false; - } - - private void handleLongClick(final Tweet tweet) { - String[] items = null; - if (AppContext.getInstance().getLoginUid() == tweet.getAuthorid()) { - items = new String[] { getResources().getString(R.string.copy), - getResources().getString(R.string.delete) }; - } else { - items = new String[] { getResources().getString(R.string.copy) }; - } - - DialogHelp.getSelectDialog(getActivity(), items, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (i == 0) { - TDevice.copyTextToBoard(HTMLUtil.delHTMLTag(tweet.getBody())); - } else if (i == 1) { - handleDeleteTweet(tweet); - } - } - }).show(); - } - - private void handleDeleteTweet(final Tweet tweet) { - DialogHelp.getConfirmDialog(getActivity(), "是否删除该动弹?", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - OSChinaApi.deleteTweet(tweet.getAuthorid(), tweet - .getId(), new DeleteTweetResponseHandler(tweet)); - } - }).show(); - } - - @Override - public void onTabReselect() { - onRefresh(); - } - - @Override - protected long getAutoRefreshTime() { - // 最新动弹3分钟刷新一次 - if (mCatalog == TweetsList.CATALOG_LATEST) { - return 3 * 60; - } - return super.getAutoRefreshTime(); - } -} \ No newline at end of file diff --git a/app/src/main/java/net/oschina/app/fragment/TweetsLikesFragment.java b/app/src/main/java/net/oschina/app/fragment/TweetsLikesFragment.java deleted file mode 100644 index 68f5c900fbe3c97294597815a7664c0eb80a9e14..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/fragment/TweetsLikesFragment.java +++ /dev/null @@ -1,183 +0,0 @@ -package net.oschina.app.fragment; - -import java.io.InputStream; -import java.io.Serializable; -import java.util.List; - -import net.oschina.app.AppContext; -import net.oschina.app.R; -import net.oschina.app.adapter.TweetLikeAdapter; -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.base.BaseListFragment; -import net.oschina.app.bean.Constants; -import net.oschina.app.bean.Entity; -import net.oschina.app.bean.Notice; -import net.oschina.app.bean.Tweet; -import net.oschina.app.bean.TweetLike; -import net.oschina.app.bean.TweetLikeList; -import net.oschina.app.bean.TweetsList; -import net.oschina.app.service.NoticeUtils; -import net.oschina.app.ui.empty.EmptyLayout; -import net.oschina.app.util.UIHelper; -import net.oschina.app.util.XmlUtils; -import net.oschina.app.viewpagerfragment.NoticeViewPagerFragment; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Bundle; -import android.view.View; -import android.widget.AdapterView; - -/** - * 赞过我动弹的列表 - * - * @date 2014年10月10日 - */ -public class TweetsLikesFragment extends BaseListFragment { - - protected static final String TAG = TweetsLikesFragment.class - .getSimpleName(); - private static final String CACHE_KEY_PREFIX = "mytweets_like_list_"; - - private boolean mIsWatingLogin; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (mCatalog > 0) { - IntentFilter filter = new IntentFilter( - Constants.INTENT_ACTION_USER_CHANGE); - filter.addAction(Constants.INTENT_ACTION_LOGOUT); - getActivity().registerReceiver(mReceiver, filter); - } - } - - @Override - public void onDestroy() { - if (mCatalog > 0) { - getActivity().unregisterReceiver(mReceiver); - } - super.onDestroy(); - } - - @Override - protected TweetLikeAdapter getListAdapter() { - return new TweetLikeAdapter(); - } - - @Override - protected String getCacheKeyPrefix() { - return CACHE_KEY_PREFIX + mCatalog; - } - - @Override - protected TweetLikeList parseList(InputStream is) throws Exception { - TweetLikeList list = XmlUtils.toBean(TweetLikeList.class, is); - return list; - } - - @Override - protected TweetLikeList readList(Serializable seri) { - return ((TweetLikeList) seri); - } - - @Override - protected void sendRequestData() { - OSChinaApi.getTweetLikeList(mHandler); - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, - long id) { - Tweet tweet = mAdapter.getItem(position).getTweet(); - if (tweet != null) { - UIHelper.showTweetDetail(view.getContext(), null, tweet.getId()); - } - } - - private BroadcastReceiver mReceiver = new BroadcastReceiver() { - - @Override - public void onReceive(Context context, Intent intent) { - setupContent(); - } - }; - - private void setupContent() { - if (AppContext.getInstance().isLogin()) { - mIsWatingLogin = false; - mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING); - requestData(true); - } else { - mCatalog = TweetsList.CATALOG_ME; - mIsWatingLogin = true; - mErrorLayout.setErrorType(EmptyLayout.NETWORK_ERROR); - mErrorLayout.setErrorMessage(getString(R.string.unlogin_tip)); - } - } - - @Override - protected void requestData(boolean refresh) { - if (AppContext.getInstance().isLogin()) { - mCatalog = AppContext.getInstance().getLoginUid(); - mIsWatingLogin = false; - super.requestData(refresh); - } else { - mIsWatingLogin = true; - mErrorLayout.setErrorType(EmptyLayout.NETWORK_ERROR); - mErrorLayout.setErrorMessage(getString(R.string.unlogin_tip)); - } - } - - @Override - public void initView(View view) { - super.initView(view); - mErrorLayout.setOnLayoutClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - if (AppContext.getInstance().isLogin()) { - mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING); - requestData(true); - } else { - UIHelper.showLoginActivity(getActivity()); - } - } - }); - } - - @Override - protected long getAutoRefreshTime() { - if (mCatalog == TweetsList.CATALOG_LATEST) { - return 3 * 60; - } - return super.getAutoRefreshTime(); - } - - @Override - protected void onRefreshNetworkSuccess() { - // TODO Auto-generated method stub - super.onRefreshNetworkSuccess(); - if (AppContext.getInstance().isLogin() - && mCatalog == AppContext.getInstance().getLoginUid() - && 4 == NoticeViewPagerFragment.sCurrentPage) { - NoticeUtils.clearNotice(Notice.TYPE_NEWLIKE); - UIHelper.sendBroadcastForNotice(getActivity()); - } - } - - protected boolean compareTo(List data, Entity enity) { - int s = data.size(); - - if (enity != null && enity instanceof TweetLike) { - TweetLike tweetLike = (TweetLike) enity; - for (int i = 0; i < s; i++) { - if (tweetLike.getUser().getId() == ((TweetLike)data.get(i)).getId()) { - return true; - } - } - } - return false; - } -} \ No newline at end of file diff --git a/app/src/main/java/net/oschina/app/fragment/UserBlogFragment.java b/app/src/main/java/net/oschina/app/fragment/UserBlogFragment.java deleted file mode 100644 index b3ae9c3e96ddc74fa9680d2437b990ebaebf890a..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/fragment/UserBlogFragment.java +++ /dev/null @@ -1,61 +0,0 @@ -package net.oschina.app.fragment; - -import java.io.InputStream; -import java.io.Serializable; - -import net.oschina.app.adapter.BlogAdapter; -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.base.BaseListFragment; -import net.oschina.app.bean.Blog; -import net.oschina.app.bean.BlogList; -import net.oschina.app.util.UIHelper; -import net.oschina.app.util.XmlUtils; -import android.view.View; -import android.widget.AdapterView; - -/** - * 用户的博客列表(用用户的id来获取) - * - * @author FireAnt(http://my.oschina.net/LittleDY) - * @created 2014年10月29日 下午5:09:13 - * - */ -public class UserBlogFragment extends BaseListFragment { - - protected static final String TAG = UserBlogFragment.class.getSimpleName(); - private static final String CACHE_KEY_PREFIX = "user_bloglist_"; - - @Override - protected BlogAdapter getListAdapter() { - return new BlogAdapter(); - } - - @Override - protected String getCacheKeyPrefix() { - return CACHE_KEY_PREFIX + mCatalog; - } - - @Override - protected BlogList parseList(InputStream is) throws Exception { - BlogList list = XmlUtils.toBean(BlogList.class, is); - return list; - } - - @Override - protected BlogList readList(Serializable seri) { - return ((BlogList) seri); - } - - @Override - protected void sendRequestData() { - OSChinaApi.getUserBlogList(mCatalog, "", mCatalog, mCurrentPage, mHandler); - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, - long id) { - Blog blog = (Blog) mAdapter.getItem(position); - if (blog != null) - UIHelper.showUrlRedirect(view.getContext(), blog.getUrl()); - } -} diff --git a/app/src/main/java/net/oschina/app/fragment/UserCenterFragment.java b/app/src/main/java/net/oschina/app/fragment/UserCenterFragment.java deleted file mode 100644 index 4acc36494451d8453a0ad9dd313eb732b3ffe5f3..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/fragment/UserCenterFragment.java +++ /dev/null @@ -1,473 +0,0 @@ -package net.oschina.app.fragment; - -import android.content.DialogInterface; -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v7.app.AlertDialog; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AbsListView; -import android.widget.AbsListView.OnScrollListener; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.ImageView; -import android.widget.ListView; -import android.widget.TextView; - -import com.loopj.android.http.AsyncHttpResponseHandler; - -import net.oschina.app.AppContext; -import net.oschina.app.R; -import net.oschina.app.adapter.ActiveAdapter; -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.base.BaseFragment; -import net.oschina.app.base.ListBaseAdapter; -import net.oschina.app.bean.Active; -import net.oschina.app.bean.Result; -import net.oschina.app.bean.ResultBean; -import net.oschina.app.bean.User; -import net.oschina.app.bean.UserInformation; -import net.oschina.app.ui.empty.EmptyLayout; -import net.oschina.app.util.DialogHelp; -import net.oschina.app.util.StringUtils; -import net.oschina.app.util.TDevice; -import net.oschina.app.util.UIHelper; -import net.oschina.app.util.XmlUtils; -import net.oschina.app.widget.AvatarView; - - -import java.io.ByteArrayInputStream; -import java.util.List; - -import butterknife.ButterKnife; -import butterknife.InjectView; -import cz.msebera.android.httpclient.Header; - -/** - * @author FireAnt(http://my.oschina.net/LittleDY) - * @version 创建时间:2014年10月29日 下午2:33:18 - * - */ - -public class UserCenterFragment extends BaseFragment implements - OnItemClickListener, OnScrollListener { - - private static final Object FEMALE = "女"; - - @InjectView(R.id.error_layout) - EmptyLayout mEmptyView; - - @InjectView(R.id.lv_user_active) - ListView mListView; - private ImageView mIvAvatar, mIvGender; - private TextView mTvName, mTvFollowing, mTvFollower, mTvSore, - mBtnPrivateMsg, mBtnFollowUser, mTvLastestLoginTime; - - private ActiveAdapter mAdapter; - private int mHisUid; - private String mHisName; - private int mUid; - private User mUser; - - private int mActivePage = 0; - - private final AsyncHttpResponseHandler mActiveHandler = new AsyncHttpResponseHandler() { - - @Override - public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { - try { - UserInformation information = XmlUtils.toBean( - UserInformation.class, new ByteArrayInputStream(arg2)); - mUser = information.getUser(); - fillUI(); - List data = information.getActiveList(); - if (mState == STATE_REFRESH) - mAdapter.clear(); - mAdapter.addData(data); - mEmptyView.setErrorType(EmptyLayout.HIDE_LAYOUT); - if (data.size() == 0 && mState == STATE_REFRESH) { - mEmptyView.setErrorType(EmptyLayout.NODATA); - mAdapter.setState(ListBaseAdapter.STATE_NO_MORE); - } else if (data.size() == 0) { - if (mState == STATE_REFRESH) - mAdapter.setState(ListBaseAdapter.STATE_NO_MORE); - else - mAdapter.setState(ListBaseAdapter.STATE_NO_MORE); - } else { - mAdapter.setState(ListBaseAdapter.STATE_LOAD_MORE); - } - } catch (Exception e) { - onFailure(arg0, arg1, arg2, e); - e.printStackTrace(); - } - } - - @Override - public void onFailure(int arg0, Header[] arg1, byte[] arg2, - Throwable arg3) { - mEmptyView.setErrorType(EmptyLayout.NETWORK_ERROR); - } - - @Override - public void onFinish() { - mState = STATE_NONE; - } - }; - - @Override - public View onCreateView(LayoutInflater inflater, - @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - super.onCreateView(inflater, container, savedInstanceState); - View view = inflater.inflate(R.layout.fragment_user_center, container, - false); - - Bundle args = getArguments(); - - mHisUid = args.getInt("his_id", 0); - mHisName = args.getString("his_name"); - mUid = AppContext.getInstance().getLoginUid(); - ButterKnife.inject(this, view); - initView(view); - - return view; - } - - @Override - public void onClick(View v) { - final int id = v.getId(); - switch (id) { - case R.id.iv_avatar: - UIHelper.showUserAvatar(getActivity(), mUser.getPortrait()); - break; - case R.id.ly_following: - UIHelper.showFriends(getActivity(), mUser.getId(), 0); - break; - case R.id.ly_follower: - UIHelper.showFriends(getActivity(), mUser.getId(), 1); - break; - case R.id.tv_follow_user: - handleUserRelation(); - break; - case R.id.tv_private_message: - if (mHisUid == AppContext.getInstance().getLoginUid()) { - AppContext.showToast("不能给自己发送留言:)"); - return; - } - if (!AppContext.getInstance().isLogin()) { - UIHelper.showLoginActivity(getActivity()); - return; - } - UIHelper.showMessageDetail(getActivity(), mHisUid, mHisName); - break; - case R.id.tv_blog: - UIHelper.showUserBlog(getActivity(), mHisUid); - break; - case R.id.tv_information: - showInformationDialog(); - break; - default: - break; - } - } - - @Override - public void initView(View view) { - mListView.setOnItemClickListener(this); - mListView.setOnScrollListener(this); - - View header = LayoutInflater.from(getActivity()).inflate( - R.layout.fragment_user_center_header, null, false); - - mIvAvatar = (ImageView) header.findViewById(R.id.iv_avatar); - mIvAvatar.setOnClickListener(this); - mIvGender = (ImageView) header.findViewById(R.id.iv_gender); - mTvName = (TextView) header.findViewById(R.id.tv_name); - mTvFollowing = (TextView) header.findViewById(R.id.tv_following_count); - header.findViewById(R.id.ly_following).setOnClickListener(this); - mTvFollower = (TextView) header.findViewById(R.id.tv_follower_count); - header.findViewById(R.id.ly_follower).setOnClickListener(this); - mTvSore = (TextView) header.findViewById(R.id.tv_score); - mTvLastestLoginTime = (TextView) header - .findViewById(R.id.tv_latest_login_time); - - mBtnPrivateMsg = (TextView) header - .findViewById(R.id.tv_private_message); - mBtnPrivateMsg.setOnClickListener(this); - mBtnFollowUser = (TextView) header.findViewById(R.id.tv_follow_user); - mBtnFollowUser.setOnClickListener(this); - - header.findViewById(R.id.tv_blog).setOnClickListener(this); - header.findViewById(R.id.tv_information).setOnClickListener(this); - - mListView.addHeaderView(header); - - mBtnPrivateMsg.setOnClickListener(this); - mBtnFollowUser.setOnClickListener(this); - - if (mAdapter == null) { - mAdapter = new ActiveAdapter(); - - fristSendGetUserInfomation(); - } - mListView.setAdapter(mAdapter); - - mEmptyView.setOnLayoutClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - fristSendGetUserInfomation(); - } - }); - } - - private void fristSendGetUserInfomation() { - mState = STATE_REFRESH; - mListView.setVisibility(View.GONE); - mEmptyView.setErrorType(EmptyLayout.NETWORK_LOADING); - sendGetUserInfomation(); - } - - private void sendGetUserInfomation() { - OSChinaApi.getUserInformation(mUid, mHisUid, mHisName, mActivePage, - mActiveHandler); - } - - private void fillUI() { - mListView.setVisibility(View.VISIBLE); - ((AvatarView) mIvAvatar).setAvatarUrl(mUser.getPortrait()); - mHisUid = mUser.getId(); - mHisName = mUser.getName(); - mTvName.setText(mHisName); - - int genderIcon = R.drawable.userinfo_icon_male; - if (FEMALE.equals(mUser.getGender())) { - genderIcon = R.drawable.userinfo_icon_female; - } - mIvGender.setBackgroundResource(genderIcon); - - mTvFollowing.setText(mUser.getFollowers() + ""); - mTvFollower.setText(mUser.getFans() + ""); - mTvSore.setText(mUser.getScore() + ""); - mTvLastestLoginTime.setText(getString(R.string.latest_login_time, - StringUtils.friendly_time(mUser.getLatestonline()))); - updateUserRelation(); - } - - private void updateUserRelation() { - switch (mUser.getRelation()) { - case User.RELATION_TYPE_BOTH: - mBtnFollowUser.setCompoundDrawablesWithIntrinsicBounds( - R.drawable.ic_follow_each_other, 0, 0, 0); - mBtnFollowUser.setText(R.string.follow_each_other); - mBtnFollowUser.setTextColor(getResources().getColor(R.color.black)); - mBtnFollowUser - .setBackgroundResource(R.drawable.btn_small_white_selector); - break; - case User.RELATION_TYPE_FANS_HIM: - mBtnFollowUser.setCompoundDrawablesWithIntrinsicBounds( - R.drawable.ic_followed, 0, 0, 0); - mBtnFollowUser.setText(R.string.unfollow_user); - mBtnFollowUser.setTextColor(getResources().getColor(R.color.black)); - mBtnFollowUser - .setBackgroundResource(R.drawable.btn_small_white_selector); - break; - case User.RELATION_TYPE_FANS_ME: - mBtnFollowUser.setCompoundDrawablesWithIntrinsicBounds( - R.drawable.ic_add_follow, 0, 0, 0); - mBtnFollowUser.setText(R.string.follow_user); - mBtnFollowUser.setTextColor(getResources().getColor(R.color.white)); - mBtnFollowUser - .setBackgroundResource(R.drawable.btn_small_green_selector); - break; - case User.RELATION_TYPE_NULL: - mBtnFollowUser.setCompoundDrawablesWithIntrinsicBounds( - R.drawable.ic_add_follow, 0, 0, 0); - mBtnFollowUser.setText(R.string.follow_user); - mBtnFollowUser.setTextColor(getResources().getColor(R.color.white)); - mBtnFollowUser - .setBackgroundResource(R.drawable.btn_small_green_selector); - break; - } - int padding = (int) TDevice.dpToPixel(20); - mBtnFollowUser.setPadding(padding, 0, padding, 0); - } - - private AlertDialog mInformationDialog; - - private void showInformationDialog() { - if (mInformationDialog == null) { - mInformationDialog = DialogHelp.getDialog(getActivity()).show(); - View view = LayoutInflater.from(getActivity()).inflate( - R.layout.fragment_user_center_information, null); - ((TextView) view.findViewById(R.id.tv_join_time)) - .setText(StringUtils.friendly_time(mUser.getJointime())); - ((TextView) view.findViewById(R.id.tv_location)) - .setText(StringUtils.getString(mUser.getFrom())); - ((TextView) view.findViewById(R.id.tv_development_platform)) - .setText(StringUtils.getString(mUser.getDevplatform())); - ((TextView) view.findViewById(R.id.tv_academic_focus)) - .setText(StringUtils.getString(mUser.getExpertise())); - mInformationDialog.setContentView(view); - } - - mInformationDialog.show(); - } - - private void handleUserRelation() { - if (mUser == null) - return; - // 判断登录 - final AppContext ac = AppContext.getInstance(); - if (!ac.isLogin()) { - UIHelper.showLoginActivity(getActivity()); - return; - } - String dialogTitle = ""; - int relationAction = 0; - switch (mUser.getRelation()) { - case User.RELATION_TYPE_BOTH: - dialogTitle = "确定取消互粉吗?"; - relationAction = User.RELATION_ACTION_DELETE; - break; - case User.RELATION_TYPE_FANS_HIM: - dialogTitle = "确定取消关注吗?"; - relationAction = User.RELATION_ACTION_DELETE; - break; - case User.RELATION_TYPE_FANS_ME: - dialogTitle = "确定关注Ta吗?"; - relationAction = User.RELATION_ACTION_ADD; - break; - case User.RELATION_TYPE_NULL: - dialogTitle = "确定关注Ta吗?"; - relationAction = User.RELATION_ACTION_ADD; - break; - } - final int ra = relationAction; - - DialogHelp.getConfirmDialog(getActivity(), dialogTitle, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - sendUpdateRelcationRequest(ra); - } - }).show(); - } - - private void sendUpdateRelcationRequest(int ra) { - OSChinaApi.updateRelation(mUid, mHisUid, ra, - new AsyncHttpResponseHandler() { - - @Override - public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { - try { - Result result = XmlUtils.toBean(ResultBean.class, - new ByteArrayInputStream(arg2)).getResult(); - if (result.OK()) { - switch (mUser.getRelation()) { - case User.RELATION_TYPE_BOTH: - mBtnFollowUser - .setCompoundDrawablesWithIntrinsicBounds( - R.drawable.ic_add_follow, - 0, 0, 0); - mBtnFollowUser - .setText(R.string.follow_user); - mBtnFollowUser.setTextColor(getResources() - .getColor(R.color.white)); - mBtnFollowUser - .setBackgroundResource(R.drawable.btn_small_green_selector); - mUser.setRelation(User.RELATION_TYPE_FANS_ME); - break; - case User.RELATION_TYPE_FANS_HIM: - mBtnFollowUser - .setCompoundDrawablesWithIntrinsicBounds( - R.drawable.ic_add_follow, - 0, 0, 0); - mBtnFollowUser - .setText(R.string.follow_user); - mBtnFollowUser.setTextColor(getResources() - .getColor(R.color.white)); - mBtnFollowUser - .setBackgroundResource(R.drawable.btn_small_green_selector); - mUser.setRelation(User.RELATION_TYPE_NULL); - break; - case User.RELATION_TYPE_FANS_ME: - mBtnFollowUser - .setCompoundDrawablesWithIntrinsicBounds( - R.drawable.ic_followed, 0, - 0, 0); - mBtnFollowUser - .setText(R.string.follow_each_other); - mBtnFollowUser.setTextColor(getResources() - .getColor(R.color.black)); - mBtnFollowUser - .setBackgroundResource(R.drawable.btn_small_white_selector); - mUser.setRelation(User.RELATION_TYPE_BOTH); - break; - case User.RELATION_TYPE_NULL: - mBtnFollowUser - .setCompoundDrawablesWithIntrinsicBounds( - R.drawable.ic_followed, 0, - 0, 0); - mBtnFollowUser - .setText(R.string.unfollow_user); - mBtnFollowUser.setTextColor(getResources() - .getColor(R.color.black)); - mBtnFollowUser - .setBackgroundResource(R.drawable.btn_small_white_selector); - mUser.setRelation(User.RELATION_TYPE_FANS_HIM); - break; - } - int padding = (int) TDevice.dpToPixel(20); - mBtnFollowUser.setPadding(padding, 0, padding, - 0); - } - AppContext.showToastShort(result.getErrorMessage()); - } catch (Exception e) { - e.printStackTrace(); - onFailure(arg0, arg1, arg2, e); - } - } - - @Override - public void onFailure(int arg0, Header[] arg1, byte[] arg2, - Throwable arg3) {} - }); - } - - @Override - public void initData() {} - - @Override - public void onItemClick(AdapterView parent, View view, int position, - long id) { - if (position - 1 < 0) { - return; - } - Active active = (Active) mAdapter.getItem(position - 1); - if (active != null) - UIHelper.showActiveRedirect(view.getContext(), active); - } - - @Override - public void onScroll(AbsListView view, int firstVisibleItem, - int visibleItemCount, int totalItemCount) { - // 数据已经全部加载,或数据为空时,或正在加载,不处理滚动事件 - if (mState == STATE_NOMORE || mState == STATE_LOADMORE - || mState == STATE_REFRESH) { - return; - } - if (mAdapter != null - && mAdapter.getDataSize() > 0 - && mListView.getLastVisiblePosition() == (mListView.getCount() - 1)) { - if (mState == STATE_NONE - && mAdapter.getState() == ListBaseAdapter.STATE_LOAD_MORE) { - mState = STATE_LOADMORE; - mActivePage++; - sendGetUserInfomation(); - } - } - } - - @Override - public void onScrollStateChanged(AbsListView view, int scrollState) {} -} diff --git a/app/src/main/java/net/oschina/app/fragment/UserFavoriteFragment.java b/app/src/main/java/net/oschina/app/fragment/UserFavoriteFragment.java deleted file mode 100644 index aae6ba005ae13aaaedd698db03257ddcf28d1c13..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/fragment/UserFavoriteFragment.java +++ /dev/null @@ -1,79 +0,0 @@ -package net.oschina.app.fragment; - -import java.io.InputStream; -import java.io.Serializable; - -import net.oschina.app.AppContext; -import net.oschina.app.adapter.UserFavoriteAdapter; -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.base.BaseListFragment; -import net.oschina.app.bean.Favorite; -import net.oschina.app.bean.FavoriteList; -import net.oschina.app.util.UIHelper; -import net.oschina.app.util.XmlUtils; -import android.view.View; -import android.widget.AdapterView; - -public class UserFavoriteFragment extends BaseListFragment { - - protected static final String TAG = UserFavoriteFragment.class - .getSimpleName(); - private static final String CACHE_KEY_PREFIX = "userfavorite_"; - - @Override - protected UserFavoriteAdapter getListAdapter() { - return new UserFavoriteAdapter(); - } - - @Override - protected String getCacheKeyPrefix() { - return CACHE_KEY_PREFIX + mCatalog; - } - - @Override - protected FavoriteList parseList(InputStream is) throws Exception { - - FavoriteList list = XmlUtils.toBean(FavoriteList.class, is); - return list; - } - - @Override - protected FavoriteList readList(Serializable seri) { - return ((FavoriteList) seri); - } - - @Override - protected void sendRequestData() { - OSChinaApi.getFavoriteList(AppContext.getInstance().getLoginUid(), - mCatalog, mCurrentPage, mHandler); - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, - long id) { - - Favorite favorite = (Favorite) mAdapter.getItem(position); - if (favorite != null) { - switch (favorite.getType()) { - - case Favorite.CATALOG_BLOGS: - UIHelper.showUrlRedirect(getActivity(), favorite.getUrl()); - break; - case Favorite.CATALOG_CODE: - UIHelper.showUrlRedirect(getActivity(), favorite.getUrl()); - break; - case Favorite.CATALOG_NEWS: - UIHelper.showUrlRedirect(getActivity(), favorite.getUrl()); - break; - case Favorite.CATALOG_SOFTWARE: - UIHelper.showUrlRedirect(getActivity(), favorite.getUrl()); - break; - case Favorite.CATALOG_TOPIC: - UIHelper.showUrlRedirect(getActivity(), favorite.getUrl()); - break; - - } - } - - } -} diff --git a/app/src/main/java/net/oschina/app/improve/account/AccountHelper.java b/app/src/main/java/net/oschina/app/improve/account/AccountHelper.java new file mode 100644 index 0000000000000000000000000000000000000000..e0194dd7b63b12c21eef15e5738703a0a5a24f8b --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/account/AccountHelper.java @@ -0,0 +1,144 @@ +package net.oschina.app.improve.account; + +import android.annotation.SuppressLint; +import android.app.ActivityManager; +import android.app.Application; +import android.content.Context; +import android.content.Intent; +import android.support.v4.content.LocalBroadcastManager; +import android.text.TextUtils; +import android.view.View; + +import net.oschina.app.api.ApiHttpClient; +import net.oschina.app.bean.Constants; +import net.oschina.app.cache.CacheManager; +import net.oschina.app.improve.bean.User; +import net.oschina.app.improve.notice.NoticeManager; +import net.oschina.app.improve.tweet.fragments.TweetFragment; +import net.oschina.app.util.TLog; +import net.oschina.common.helper.SharedPreferencesHelper; + +import cz.msebera.android.httpclient.Header; + +/** + * 账户辅助类, + * 用于更新用户信息和保存当前账户等操作 + */ +public final class AccountHelper { + private User user; + private Application application; + @SuppressLint("StaticFieldLeak") + private static AccountHelper instances; + + private AccountHelper(Application application) { + this.application = application; + } + + public static void init(Application application) { + instances = new AccountHelper(application); + } + + public static boolean isLogin() { + return getUserId() > 0 && !TextUtils.isEmpty(getCookie()); + } + + public static String getCookie() { + String cookie = getUser().getCookie(); + return cookie == null ? "" : cookie; + } + + public static long getUserId() { + return getUser().getId(); + } + + public synchronized static User getUser() { + if (instances == null) { + TLog.error("AccountHelper instances is null, you need call init() method."); + return new User(); + } + if (instances.user == null) + instances.user = SharedPreferencesHelper.loadFormSource(instances.application, User.class); + if (instances.user == null) + instances.user = new User(); + return instances.user; + } + + public static void updateUserCache(User user) { + if (user == null) + return; + // 保留Cookie信息 + if (TextUtils.isEmpty(user.getCookie()) && instances.user != user) + user.setCookie(instances.user.getCookie()); + instances.user = user; + SharedPreferencesHelper.save(instances.application, user); + } + + private static void clearUserCache() { + instances.user = null; + SharedPreferencesHelper.remove(instances.application, User.class); + } + + public static void login(User user, Header[] headers) { + // 更新Cookie + String cookie = ApiHttpClient.getCookie(headers); + user.setCookie(cookie); + ApiHttpClient.setCookieHeader(cookie); + + // 保存缓存 + updateUserCache(user); + // 登陆成功,重新启动消息服务 + NoticeManager.init(instances.application); + } + + /** + * 退出登陆操作需要传递一个View协助完成延迟检测操作 + * + * @param view View + * @param runnable 当清理完成后回调方法 + */ + public static void logout(final View view, final Runnable runnable) { + // 清除用户缓存 + clearUserCache(); + // 等待缓存清理完成 + view.postDelayed(new Runnable() { + @Override + public void run() { + view.removeCallbacks(this); + User user = SharedPreferencesHelper.load(instances.application, User.class); + // 判断当前用户信息是否清理成功 + if (user == null || user.getId() <= 0) { + clearAndPostBroadcast(instances.application); + runnable.run(); + } else { + view.postDelayed(this, 200); + } + } + }, 200); + + } + + /** + * 当前用户信息清理完成后调用方法清理服务等信息 + * + * @param application Application + */ + private static void clearAndPostBroadcast(Application application) { + // 清理网络相关 + ApiHttpClient.destroyAndRestore(application); + + // 用户退出时清理红点并退出服务 + NoticeManager.clear(application, NoticeManager.FLAG_CLEAR_ALL); + NoticeManager.exitServer(application); + + // 清理动弹对应数据 + CacheManager.deleteObject(application, TweetFragment.CACHE_USER_TWEET); + + ActivityManager activityManager = (ActivityManager) application.getSystemService(Context.ACTIVITY_SERVICE); + activityManager.killBackgroundProcesses("net.oschina.app.tweet.TweetPublishService"); + activityManager.killBackgroundProcesses("net.oschina.app.notice.NoticeServer"); + + // Logout 广播 + Intent intent = new Intent(Constants.INTENT_ACTION_LOGOUT); + LocalBroadcastManager.getInstance(application).sendBroadcast(intent); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/account/activity/LoginActivity.java b/app/src/main/java/net/oschina/app/improve/account/activity/LoginActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..33650a75bc9f526208ab45fcfa985e646275f7ea --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/account/activity/LoginActivity.java @@ -0,0 +1,843 @@ +package net.oschina.app.improve.account.activity; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.graphics.Rect; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.content.SharedPreferencesCompat; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewTreeObserver; +import android.view.animation.DecelerateInterpolator; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; +import com.sina.weibo.sdk.auth.Oauth2AccessToken; +import com.sina.weibo.sdk.auth.WeiboAuthListener; +import com.sina.weibo.sdk.auth.sso.SsoHandler; +import com.sina.weibo.sdk.exception.WeiboException; +import com.tencent.tauth.IUiListener; +import com.tencent.tauth.Tencent; +import com.tencent.tauth.UiError; + +import net.oschina.app.AppContext; +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.account.base.AccountBaseActivity; +import net.oschina.app.improve.account.constants.UserConstants; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.bean.User; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.util.TDevice; +import net.oschina.open.constants.OpenConstant; +import net.oschina.open.factory.OpenBuilder; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.lang.reflect.Type; + +import butterknife.Bind; +import butterknife.OnClick; +import cz.msebera.android.httpclient.Header; + + +/** + * Created by fei on 2016/10/14. + * desc: + */ + +public class LoginActivity extends AccountBaseActivity implements View.OnClickListener, IUiListener, View.OnFocusChangeListener, ViewTreeObserver.OnGlobalLayoutListener { + + public static final String HOLD_USERNAME_KEY = "holdUsernameKey"; + + @Bind(R.id.ly_retrieve_bar) + LinearLayout mLayBackBar; + + @Bind(R.id.iv_login_logo) + ImageView mIvLoginLogo; + + @Bind(R.id.ll_login_username) + LinearLayout mLlLoginUsername; + @Bind(R.id.et_login_username) + EditText mEtLoginUsername; + @Bind(R.id.iv_login_username_del) + ImageView mIvLoginUsernameDel; + + @Bind(R.id.ll_login_pwd) + LinearLayout mLlLoginPwd; + @Bind(R.id.et_login_pwd) + EditText mEtLoginPwd; + @Bind(R.id.iv_login_pwd_del) + ImageView mIvLoginPwdDel; + + @Bind(R.id.iv_login_hold_pwd) + ImageView mIvHoldPwd; + @Bind(R.id.tv_login_forget_pwd) + TextView mTvLoginForgetPwd; + + @Bind(R.id.bt_login_submit) + Button mBtLoginSubmit; + @Bind(R.id.bt_login_register) + Button mBtLoginRegister; + + @Bind(R.id.ll_login_layer) + View mLlLoginLayer; + @Bind(R.id.ll_login_pull) + LinearLayout mLlLoginPull; + + @Bind(R.id.ll_login_options) + LinearLayout mLlLoginOptions; + + @Bind(R.id.ib_login_weibo) + ImageView mIbLoginWeiBo; + @Bind(R.id.ib_login_wx) + ImageView mIbLoginWx; + @Bind(R.id.ib_login_qq) + ImageView mImLoginQq; + + private int openType; + private SsoHandler mSsoHandler; + private Tencent mTencent; + + + private TextHttpResponseHandler mHandler = new TextHttpResponseHandler() { + + @Override + public void onStart() { + super.onStart(); + showFocusWaitDialog(); + } + + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + requestFailureHint(throwable); + } + + @SuppressWarnings("ConstantConditions") + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + + Type type = new TypeToken>() { + }.getType(); + + GsonBuilder gsonBuilder = new GsonBuilder(); + ResultBean resultBean = gsonBuilder.create().fromJson(responseString, type); + if (resultBean.isSuccess()) { + User user = resultBean.getResult(); + AccountHelper.login(user, headers); + hideKeyBoard(getCurrentFocus().getWindowToken()); + AppContext.showToast(R.string.login_success_hint); + setResult(RESULT_OK); + sendLocalReceiver(); + } else { + showToastForKeyBord(resultBean.getMessage()); + } + + } + + @Override + public void onFinish() { + super.onFinish(); + hideWaitDialog(); + } + + @Override + public void onCancel() { + super.onCancel(); + hideWaitDialog(); + } + }; + private int mLogoHeight; + private int mLogoWidth; + + /** + * hold account information + */ + private void holdAccount() { + String username = mEtLoginUsername.getText().toString().trim(); + //String inputPwd = mEtLoginPwd.getText().toString().trim(); + + SharedPreferences sp = getSharedPreferences(UserConstants.HOLD_ACCOUNT, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sp.edit(); + if (!TextUtils.isEmpty(username)) { + editor.putString(HOLD_USERNAME_KEY, username); + } + SharedPreferencesCompat.EditorCompat.getInstance().apply(editor); + } + + /** + * show the login activity + * + * @param context context + */ + public static void show(Context context) { + Intent intent = new Intent(context, LoginActivity.class); + context.startActivity(intent); + } + + /** + * show the login activity + * + * @param context context + */ + public static void show(Activity context, int requestCode) { + Intent intent = new Intent(context, LoginActivity.class); + context.startActivityForResult(intent, requestCode); + } + + /** + * show the login activity + * + * @param fragment fragment + */ + public static void show(Fragment fragment, int requestCode) { + Intent intent = new Intent(fragment.getActivity(), LoginActivity.class); + fragment.startActivityForResult(intent, requestCode); + } + + @Override + protected int getContentView() { + return R.layout.activity_main_login; + } + + @Override + protected void initWidget() { + super.initWidget(); + mLlLoginLayer.setVisibility(View.GONE); + mEtLoginUsername.setOnFocusChangeListener(this); + mEtLoginUsername.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @SuppressWarnings("deprecation") + @Override + public void afterTextChanged(Editable s) { + String username = s.toString().trim(); + if (username.length() > 0) { + mLlLoginUsername.setBackgroundResource(R.drawable.bg_login_input_ok); + mIvLoginUsernameDel.setVisibility(View.VISIBLE); + } else { + mLlLoginUsername.setBackgroundResource(R.drawable.bg_login_input_ok); + mIvLoginUsernameDel.setVisibility(View.INVISIBLE); + } + + String pwd = mEtLoginPwd.getText().toString().trim(); + if (!TextUtils.isEmpty(pwd)) { + mBtLoginSubmit.setBackgroundResource(R.drawable.bg_login_submit); + mBtLoginSubmit.setTextColor(getResources().getColor(R.color.white)); + } else { + mBtLoginSubmit.setBackgroundResource(R.drawable.bg_login_submit_lock); + mBtLoginSubmit.setTextColor(getResources().getColor(R.color.account_lock_font_color)); + } + + } + }); + + mEtLoginPwd.setOnFocusChangeListener(this); + mEtLoginPwd.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @SuppressWarnings("deprecation") + @Override + public void afterTextChanged(Editable s) { + int length = s.length(); + if (length > 0) { + mLlLoginPwd.setBackgroundResource(R.drawable.bg_login_input_ok); + mIvLoginPwdDel.setVisibility(View.VISIBLE); + } else { + mIvLoginPwdDel.setVisibility(View.INVISIBLE); + } + + String username = mEtLoginUsername.getText().toString().trim(); + if (TextUtils.isEmpty(username)) { + showToastForKeyBord(R.string.message_username_null); + } + String pwd = mEtLoginPwd.getText().toString().trim(); + if (!TextUtils.isEmpty(pwd)) { + mBtLoginSubmit.setBackgroundResource(R.drawable.bg_login_submit); + mBtLoginSubmit.setTextColor(getResources().getColor(R.color.white)); + } else { + mBtLoginSubmit.setBackgroundResource(R.drawable.bg_login_submit_lock); + mBtLoginSubmit.setTextColor(getResources().getColor(R.color.account_lock_font_color)); + } + } + }); + + TextView label = (TextView) mLayBackBar.findViewById(R.id.tv_navigation_label); + label.setVisibility(View.INVISIBLE); + + } + + @Override + protected void initData() { + super.initData();//必须要,用来注册本地广播 + + //初始化控件状态数据 + SharedPreferences sp = getSharedPreferences(UserConstants.HOLD_ACCOUNT, Context.MODE_PRIVATE); + String holdUsername = sp.getString(HOLD_USERNAME_KEY, null); + //String holdPwd = sp.getString(HOLD_PWD_KEY, null); + //int holdStatus = sp.getInt(HOLD_PWD_STATUS_KEY, 0);//0第一次默认/1用户设置保存/2用户设置未保存 + + mEtLoginUsername.setText(holdUsername); + +// if (!TextUtils.isEmpty(holdPwd)) { +// byte[] bytes = holdPwd.getBytes(); +// byte[] decode = Base64.decode(bytes, 0, bytes.length, Base64.DEFAULT); +// try { +// String tempPwd = new String(decode, 0, decode.length, "utf-8"); +// +// mEtLoginPwd.setText(tempPwd); +// } catch (UnsupportedEncodingException e) { +// e.printStackTrace(); +// } +// } else { +// mEtLoginPwd.setText(null); +// } + // updateHoldPwd(holdStatus); + // mHoldPwd = holdStatus; + } + + @Override + protected void onResume() { + super.onResume(); + mLayBackBar.getViewTreeObserver().addOnGlobalLayoutListener(this); + } + + @SuppressWarnings("ConstantConditions") + @Override + protected void onDestroy() { + super.onDestroy(); + hideKeyBoard(getCurrentFocus().getWindowToken()); + mLayBackBar.getViewTreeObserver().removeOnGlobalLayoutListener(this); + } + + @SuppressWarnings("ConstantConditions") + @OnClick({R.id.ib_navigation_back, R.id.et_login_username, R.id.et_login_pwd, R.id.tv_login_forget_pwd, + R.id.iv_login_hold_pwd, R.id.bt_login_submit, R.id.bt_login_register, R.id.ll_login_pull, + R.id.ib_login_weibo, R.id.ib_login_wx, R.id.ib_login_qq, R.id.ll_login_layer, + R.id.iv_login_username_del, R.id.iv_login_pwd_del, R.id.lay_login_container}) + @Override + public void onClick(View v) { + int id = v.getId(); + switch (id) { + case R.id.ib_navigation_back: + finish(); + break; + case R.id.et_login_username: + mEtLoginPwd.clearFocus(); + mEtLoginUsername.setFocusableInTouchMode(true); + mEtLoginUsername.requestFocus(); + break; + case R.id.et_login_pwd: + mEtLoginUsername.clearFocus(); + mEtLoginPwd.setFocusableInTouchMode(true); + mEtLoginPwd.requestFocus(); + break; + case R.id.tv_login_forget_pwd: + //忘记密码 + RetrieveActivity.show(LoginActivity.this); + break; + case R.id.bt_login_submit: + //用户登录 + loginRequest(); + break; + case R.id.iv_login_hold_pwd: + //记住密码 + case R.id.bt_login_register: + RegisterStepOneActivity.show(LoginActivity.this); + break; + case R.id.ll_login_layer: + case R.id.ll_login_pull: + + mLlLoginPull.animate().cancel(); + mLlLoginLayer.animate().cancel(); + + int height = mLlLoginOptions.getHeight(); + float progress = (mLlLoginLayer.getTag() != null && mLlLoginLayer.getTag() instanceof Float) ? + (float) mLlLoginLayer.getTag() : 1; + int time = (int) (360 * progress); + + if (mLlLoginPull.getTag() != null) { + mLlLoginPull.setTag(null); + glide(height, progress, time); + } else { + mLlLoginPull.setTag(true); + upGlide(height, progress, time); + } + break; + case R.id.ib_login_weibo: + weiBoLogin(); + break; + case R.id.ib_login_wx: + //微信登录 + wechatLogin(); + break; + case R.id.ib_login_qq: + //QQ登录 + tencentLogin(); + break; + case R.id.iv_login_username_del: + mEtLoginUsername.setText(null); + break; + case R.id.iv_login_pwd_del: + mEtLoginPwd.setText(null); + break; + case R.id.lay_login_container: + hideKeyBoard(getCurrentFocus().getWindowToken()); + break; + default: + break; + } + + } + + /** + * login tencent + */ + private void tencentLogin() { + showWaitDialog(R.string.login_tencent_hint); + openType = OpenConstant.TENCENT; + mTencent = OpenBuilder.with(this) + .useTencent(OpenConstant.QQ_APP_ID) + .login(this, new OpenBuilder.Callback() { + @Override + public void onFailed() { + hideWaitDialog(); + } + + @Override + public void onSuccess() { + //hideWaitDialog(); + } + }); + } + + /** + * login wechat + */ + private void wechatLogin() { + showWaitDialog(R.string.login_wechat_hint); + openType = OpenConstant.WECHAT; + OpenBuilder.with(this) + .useWechat(OpenConstant.WECHAT_APP_ID) + .login(new OpenBuilder.Callback() { + @Override + public void onFailed() { + hideWaitDialog(); + AppContext.showToast(R.string.login_hint); + } + + @Override + public void onSuccess() { + //hideWaitDialog(); + } + }); + } + + /** + * login weiBo + */ + private void weiBoLogin() { + showWaitDialog(R.string.login_webo_hint); + openType = OpenConstant.SINA; + mSsoHandler = OpenBuilder.with(this) + .useWeibo(OpenConstant.WB_APP_KEY) + .login(new WeiboAuthListener() { + @Override + public void onComplete(Bundle bundle) { + hideWaitDialog(); + Oauth2AccessToken oauth2AccessToken = Oauth2AccessToken.parseAccessToken(bundle); + + if (oauth2AccessToken.isSessionValid()) { + try { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("openid", oauth2AccessToken.getUid()); + jsonObject.put("expires_in", oauth2AccessToken.getExpiresTime()); + jsonObject.put("refresh_token", oauth2AccessToken.getRefreshToken()); + jsonObject.put("access_token", oauth2AccessToken.getToken()); + + OSChinaApi.openLogin(OSChinaApi.LOGIN_WEIBO, jsonObject.toString(), mHandler); + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + + @Override + public void onWeiboException(WeiboException e) { + e.printStackTrace(); + hideWaitDialog(); + } + + @Override + public void onCancel() { + hideWaitDialog(); + } + }); + } + + + /** + * menu up glide + * + * @param height height + * @param progress progress + * @param time time + */ + private void upGlide(int height, float progress, int time) { + mLlLoginPull.animate() + .translationYBy(height * progress) + .translationY(0) + .setDuration(time) + .start(); + mLlLoginLayer.animate() + .alphaBy(1 - progress) + .alpha(1) + .setDuration(time) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + mLlLoginLayer.setVisibility(View.VISIBLE); + } + + @Override + public void onAnimationCancel(Animator animation) { + if (animation instanceof ValueAnimator) { + mLlLoginLayer.setTag(((ValueAnimator) animation).getAnimatedValue()); + } + } + + @Override + public void onAnimationEnd(Animator animation) { + if (animation instanceof ValueAnimator) { + mLlLoginLayer.setTag(((ValueAnimator) animation).getAnimatedValue()); + } + } + }) + .start(); + } + + /** + * menu glide + * + * @param height height + * @param progress progress + * @param time time + */ + private void glide(int height, float progress, int time) { + mLlLoginPull.animate() + .translationYBy(height - height * progress) + .translationY(height) + .setDuration(time) + .start(); + + mLlLoginLayer.animate() + .alphaBy(1 * progress) + .alpha(0) + .setDuration(time) + .setListener(new AnimatorListenerAdapter() { + + @Override + public void onAnimationCancel(Animator animation) { + if (animation instanceof ValueAnimator) { + mLlLoginLayer.setTag(((ValueAnimator) animation).getAnimatedValue()); + } + } + + @Override + public void onAnimationEnd(Animator animation) { + if (animation instanceof ValueAnimator) { + mLlLoginLayer.setTag(((ValueAnimator) animation).getAnimatedValue()); + } + mLlLoginLayer.setVisibility(View.GONE); + } + }) + .start(); + } + + @SuppressWarnings("ConstantConditions") + private void loginRequest() { + + String tempUsername = mEtLoginUsername.getText().toString().trim(); + String tempPwd = mEtLoginPwd.getText().toString().trim(); + + + if (!TextUtils.isEmpty(tempPwd) && !TextUtils.isEmpty(tempUsername)) { + //登录成功,请求数据进入用户个人中心页面 + + if (TDevice.hasInternet()) { + requestLogin(tempUsername, tempPwd); + } else { + showToastForKeyBord(R.string.footer_type_net_error); + } + + } else { + showToastForKeyBord(R.string.login_input_username_hint_error); + } + + } + + private void requestLogin(String tempUsername, String tempPwd) { + OSChinaApi.login(tempUsername, getSha1(tempPwd), new TextHttpResponseHandler() { + + @Override + public void onStart() { + super.onStart(); + showFocusWaitDialog(); + } + + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + requestFailureHint(throwable); + } + + @SuppressWarnings("ConstantConditions") + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + + try { + Type type = new TypeToken>() { + }.getType(); + + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, type); + if (resultBean.isSuccess()) { + User user = resultBean.getResult(); + AccountHelper.login(user, headers); + holdAccount(); + hideKeyBoard(getCurrentFocus().getWindowToken()); + AppContext.showToast(R.string.login_success_hint); + setResult(RESULT_OK); + sendLocalReceiver(); + } else { + int code = resultBean.getCode(); + String message = resultBean.getMessage(); + if (code == 211) { + mEtLoginPwd.setFocusableInTouchMode(false); + mEtLoginPwd.clearFocus(); + mEtLoginUsername.requestFocus(); + mEtLoginUsername.setFocusableInTouchMode(true); + mLlLoginUsername.setBackgroundResource(R.drawable.bg_login_input_error); + } else if (code == 212) { + mEtLoginUsername.setFocusableInTouchMode(false); + mEtLoginUsername.clearFocus(); + mEtLoginPwd.requestFocus(); + mEtLoginPwd.setFocusableInTouchMode(true); + message += "," + getResources().getString(R.string.message_pwd_error); + mLlLoginPwd.setBackgroundResource(R.drawable.bg_login_input_error); + } + showToastForKeyBord(message); + //更新失败应该是不进行任何的本地操作 + } + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + } + + @Override + public void onFinish() { + super.onFinish(); + hideWaitDialog(); + } + + @Override + public void onCancel() { + super.onCancel(); + hideWaitDialog(); + } + }); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + + tencentOnActivityResult(data); + weiBoOnActivityResult(requestCode, resultCode, data); + + super.onActivityResult(requestCode, resultCode, data); + } + + /** + * weiBo Activity Result + * + * @param requestCode requestCode + * @param resultCode resultCode + * @param data data + */ + private void weiBoOnActivityResult(int requestCode, int resultCode, Intent data) { + if (openType == OpenConstant.SINA) { + // SSO 授权回调 + // 重要:发起 SSO 登陆的 Activity 必须重写 onActivityResults + if (mSsoHandler != null) + mSsoHandler.authorizeCallBack(requestCode, resultCode, data); + } + } + + /** + * tencent Activity Result + * + * @param data data + */ + @SuppressWarnings("deprecation") + private void tencentOnActivityResult(Intent data) { + if (openType == OpenConstant.TENCENT) { + // 对于tencent + // 注:在某些低端机上调用登录后,由于内存紧张导致APP被系统回收,登录成功后无法成功回传数据。 + if (mTencent != null) { + mTencent.handleLoginData(data, this); + } + } + } + + /** + * tencent callback + * + * @param o json + */ + @Override + public void onComplete(Object o) { + JSONObject jsonObject = (JSONObject) o; + OSChinaApi.openLogin(OSChinaApi.LOGIN_QQ, jsonObject.toString(), mHandler); + hideWaitDialog(); + } + + /** + * tencent callback + * + * @param uiError uiError + */ + @Override + public void onError(UiError uiError) { + hideWaitDialog(); + } + + + /** + * tencent callback + */ + @Override + public void onCancel() { + hideWaitDialog(); + } + + @Override + public void onFocusChange(View v, boolean hasFocus) { + + int id = v.getId(); + + if (id == R.id.et_login_username) { + if (hasFocus) { + mLlLoginUsername.setActivated(true); + mLlLoginPwd.setActivated(false); + } + } else { + if (hasFocus) { + mLlLoginPwd.setActivated(true); + mLlLoginUsername.setActivated(false); + } + } + } + + + @Override + public void onGlobalLayout() { + + final ImageView ivLogo = this.mIvLoginLogo; + Rect KeypadRect = new Rect(); + + mLayBackBar.getWindowVisibleDisplayFrame(KeypadRect); + + int screenHeight = mLayBackBar.getRootView().getHeight(); + + int keypadHeight = screenHeight - KeypadRect.bottom; + + if (keypadHeight > 0) { + updateKeyBoardActiveStatus(true); + } else { + updateKeyBoardActiveStatus(false); + } + if (keypadHeight > 0 && ivLogo.getTag() == null) { + final int height = ivLogo.getHeight(); + final int width = ivLogo.getWidth(); + this.mLogoHeight = height; + this.mLogoWidth = width; + ivLogo.setTag(true); + ValueAnimator valueAnimator = ValueAnimator.ofFloat(1, 0); + valueAnimator.setDuration(400).setInterpolator(new DecelerateInterpolator()); + valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + float animatedValue = (float) animation.getAnimatedValue(); + ViewGroup.LayoutParams layoutParams = ivLogo.getLayoutParams(); + layoutParams.height = (int) (height * animatedValue); + layoutParams.width = (int) (width * animatedValue); + ivLogo.requestLayout(); + ivLogo.setAlpha(animatedValue); + } + }); + + if (valueAnimator.isRunning()) { + valueAnimator.cancel(); + } + valueAnimator.start(); + + + } else if (keypadHeight == 0 && ivLogo.getTag() != null) { + final int height = mLogoHeight; + final int width = mLogoWidth; + ivLogo.setTag(null); + ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1); + valueAnimator.setDuration(400).setInterpolator(new DecelerateInterpolator()); + valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + float animatedValue = (float) animation.getAnimatedValue(); + ViewGroup.LayoutParams layoutParams = ivLogo.getLayoutParams(); + layoutParams.height = (int) (height * animatedValue); + layoutParams.width = (int) (width * animatedValue); + ivLogo.requestLayout(); + ivLogo.setAlpha(animatedValue); + } + }); + + if (valueAnimator.isRunning()) { + valueAnimator.cancel(); + } + valueAnimator.start(); + + } + + } +} diff --git a/app/src/main/java/net/oschina/app/improve/account/activity/RegisterStepOneActivity.java b/app/src/main/java/net/oschina/app/improve/account/activity/RegisterStepOneActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..341487ae5fa0934adfa7de71a25eee6588fdd537 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/account/activity/RegisterStepOneActivity.java @@ -0,0 +1,508 @@ +package net.oschina.app.improve.account.activity; + +import android.animation.ValueAnimator; +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.Intent; +import android.graphics.Rect; +import android.os.CountDownTimer; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.View; +import android.view.ViewTreeObserver; +import android.view.animation.DecelerateInterpolator; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.AppContext; +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.account.base.AccountBaseActivity; +import net.oschina.app.improve.account.bean.PhoneToken; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.utils.AssimilateUtils; +import net.oschina.app.util.TDevice; + +import java.lang.reflect.Type; + +import butterknife.Bind; +import butterknife.OnClick; +import cz.msebera.android.httpclient.Header; + +/** + * Created by fei + * on 2016/10/14. + * desc: + */ + +public class RegisterStepOneActivity extends AccountBaseActivity implements View.OnClickListener, View.OnFocusChangeListener, + ViewTreeObserver.OnGlobalLayoutListener { + + @Bind(R.id.ly_retrieve_bar) + LinearLayout mLayBackBar; + + @Bind(R.id.iv_login_logo) + ImageView mIvLogo; + + @Bind(R.id.ll_register_phone) + LinearLayout mLlRegisterPhone; + @Bind(R.id.et_register_username) + EditText mEtRegisterUsername; + @Bind(R.id.iv_register_username_del) + ImageView mIvRegisterDel; + + @Bind(R.id.ll_register_sms_code) + LinearLayout mLlRegisterSmsCode; + @Bind(R.id.et_register_auth_code) + EditText mEtRegisterAuthCode; + @Bind(R.id.tv_register_sms_call) + TextView mTvRegisterSmsCall; + @Bind(R.id.bt_register_submit) + Button mBtRegisterSubmit; + + private boolean mMachPhoneNum; + + private CountDownTimer mTimer; + + private int mRequestType = 1;//1. 请求发送验证码 2.请求phoneToken + + + private TextHttpResponseHandler mHandler = new TextHttpResponseHandler() { + + @Override + public void onStart() { + super.onStart(); + showWaitDialog(R.string.progress_submit); + } + + @Override + public void onFinish() { + super.onFinish(); + hideWaitDialog(); + } + + @Override + public void onCancel() { + super.onCancel(); + hideWaitDialog(); + } + + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + if (mRequestType == 1) { + if (mTimer != null) { + mTimer.onFinish(); + mTimer.cancel(); + } + } + requestFailureHint(throwable); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + + try { + switch (mRequestType) { + //第一步请求发送验证码 + case 1: + Type type = new TypeToken() { + }.getType(); + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, type); + int code = resultBean.getCode(); + switch (code) { + case 1: + //发送验证码成功,请求进入下一步 + //意味着我们可以进行第二次请求了,获取phoneToken + //mRequestType = 2; + AppContext.showToast(R.string.send_sms_code_success_hint); + mEtRegisterAuthCode.setText(null); + break; + case 218: + //手机号已被注册,提示重新输入 + mLlRegisterPhone.setBackgroundResource(R.drawable.bg_login_input_error); + showToastForKeyBord(resultBean.getMessage()); + break; + case 0: + //异常错误,发送验证码失败,回收timer,需重新请求发送验证码 + if (mTimer != null) { + mTimer.onFinish(); + mTimer.cancel(); + } + showToastForKeyBord(resultBean.getMessage()); + break; + default: + break; + } + + break; + //第二步请求进行注册 + case 2: + + Type phoneType = new TypeToken>() { + }.getType(); + + ResultBean phoneTokenResultBean = AppOperator.createGson().fromJson(responseString, phoneType); + int smsCode = phoneTokenResultBean.getCode(); + switch (smsCode) { + case 1://注册成功,进行用户信息填写 + if (phoneTokenResultBean.isSuccess()) { + PhoneToken phoneToken = phoneTokenResultBean.getResult(); + if (phoneToken != null) { + if (mTimer != null) { + mTimer.onFinish(); + mTimer.cancel(); + } + RegisterStepTwoActivity.show(RegisterStepOneActivity.this, phoneToken); + } + } else { + showToastForKeyBord(phoneTokenResultBean.getMessage()); + } + break; + case 215://注册失败,手机验证码错误 + mLlRegisterSmsCode.setBackgroundResource(R.drawable.bg_login_input_error); + showToastForKeyBord(phoneTokenResultBean.getMessage()); + break; + default: + break; + } + + break; + default: + break; + } + + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + + } + }; + private int mLogoHeight; + private int mLogoWidth; + + /** + * show the register activity + * + * @param context context + */ + public static void show(Context context) { + Intent intent = new Intent(context, RegisterStepOneActivity.class); + context.startActivity(intent); + } + + @Override + protected int getContentView() { + return R.layout.activity_main_register_step_one; + } + + @Override + protected void initWidget() { + super.initWidget(); + + TextView label = (TextView) mLayBackBar.findViewById(R.id.tv_navigation_label); + label.setVisibility(View.INVISIBLE); + + mEtRegisterUsername.addTextChangedListener( + new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + int length = s.length(); + if (length > 0) { + mIvRegisterDel.setVisibility(View.VISIBLE); + } else { + mIvRegisterDel.setVisibility(View.INVISIBLE); + } + } + + @SuppressWarnings("deprecation") + @Override + public void afterTextChanged(Editable s) { + int length = s.length(); + String input = s.toString(); + mMachPhoneNum = AssimilateUtils.machPhoneNum(input); + + if (mMachPhoneNum) { + String smsCode = mEtRegisterAuthCode.getText().toString().trim(); + + if (!TextUtils.isEmpty(smsCode)) { + mBtRegisterSubmit.setBackgroundResource(R.drawable.bg_login_submit); + mBtRegisterSubmit.setTextColor(getResources().getColor(R.color.white)); + } else { + mBtRegisterSubmit.setBackgroundResource(R.drawable.bg_login_submit_lock); + mBtRegisterSubmit.setTextColor(getResources().getColor(R.color.account_lock_font_color)); + } + } else { + mBtRegisterSubmit.setBackgroundResource(R.drawable.bg_login_submit_lock); + mBtRegisterSubmit.setTextColor(getResources().getColor(R.color.account_lock_font_color)); + } + + if (length > 0 && length < 11) { + mLlRegisterPhone.setBackgroundResource(R.drawable.bg_login_input_error); + mTvRegisterSmsCall.setAlpha(0.4f); + } else if (length == 11) { + if (mMachPhoneNum) { + mLlRegisterPhone.setBackgroundResource(R.drawable.bg_login_input_ok); + if (mTvRegisterSmsCall.getTag() == null) { + mTvRegisterSmsCall.setAlpha(1.0f); + } else { + mTvRegisterSmsCall.setAlpha(0.4f); + } + } else { + mLlRegisterPhone.setBackgroundResource(R.drawable.bg_login_input_error); + showToastForKeyBord(R.string.hint_username_ok); + mTvRegisterSmsCall.setAlpha(0.4f); + } + } else if (length > 11) { + mTvRegisterSmsCall.setAlpha(0.4f); + mLlRegisterPhone.setBackgroundResource(R.drawable.bg_login_input_error); + } else if (length <= 0) { + mTvRegisterSmsCall.setAlpha(0.4f); + mLlRegisterPhone.setBackgroundResource(R.drawable.bg_login_input_ok); + } + + + } + } + + ); + mEtRegisterUsername.setOnFocusChangeListener(this); + mEtRegisterAuthCode.setOnFocusChangeListener(this); + mEtRegisterAuthCode.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @SuppressWarnings("deprecation") + @Override + public void afterTextChanged(Editable s) { + int length = s.length(); + if (length > 0 && mMachPhoneNum) { + mBtRegisterSubmit.setBackgroundResource(R.drawable.bg_login_submit); + mBtRegisterSubmit.setTextColor(getResources().getColor(R.color.white)); + } else { + mBtRegisterSubmit.setBackgroundResource(R.drawable.bg_login_submit_lock); + mBtRegisterSubmit.setTextColor(getResources().getColor(R.color.account_lock_font_color)); + } + mLlRegisterSmsCode.setBackgroundResource(R.drawable.bg_login_input_ok); + } + }); + } + + + @Override + protected void initData() { + super.initData();//必须要调用,用来注册本地广播 + } + + @Override + protected void onResume() { + super.onResume(); + mLayBackBar.getViewTreeObserver().addOnGlobalLayoutListener(this); + } + + @SuppressWarnings("ConstantConditions") + @Override + protected void onDestroy() { + super.onDestroy(); + hideKeyBoard(getCurrentFocus().getWindowToken()); + mLayBackBar.getViewTreeObserver().removeOnGlobalLayoutListener(this); + } + + @SuppressWarnings("ConstantConditions") + @OnClick({R.id.ib_navigation_back, R.id.iv_register_username_del, R.id.tv_register_sms_call, + R.id.bt_register_submit, R.id.lay_register_one_container}) + @Override + public void onClick(View v) { + int id = v.getId(); + switch (id) { + case R.id.ib_navigation_back: + finish(); + break; + case R.id.iv_register_username_del: + mEtRegisterUsername.setText(null); + break; + case R.id.tv_register_sms_call: + requestSmsCode(); + break; + case R.id.bt_register_submit: + requestRegister(); + // RegisterStepTwoActivity.show(this,null); + break; + case R.id.lay_register_one_container: + hideKeyBoard(getCurrentFocus().getWindowToken()); + break; + default: + break; + } + + } + + private void requestRegister() { + + String smsCode = mEtRegisterAuthCode.getText().toString().trim(); + if (!mMachPhoneNum || TextUtils.isEmpty(smsCode)) { + //showToastForKeyBord(R.string.hint_username_ok); + return; + } + + if (!TDevice.hasInternet()) { + showToastForKeyBord(R.string.tip_network_error); + return; + } + + mRequestType = 2; + String phoneNumber = mEtRegisterUsername.getText().toString().trim(); + OSChinaApi.validateRegisterInfo(phoneNumber, smsCode, mHandler); + } + + private void requestSmsCode() { + if (!mMachPhoneNum) { + //showToastForKeyBord(R.string.hint_username_ok); + return; + } + if (!TDevice.hasInternet()) { + showToastForKeyBord(R.string.tip_network_error); + return; + } + + if (mTvRegisterSmsCall.getTag() == null) { + mRequestType = 1; + mTvRegisterSmsCall.setAlpha(0.6f); + mTvRegisterSmsCall.setTag(true); + mTimer = new CountDownTimer(60 * 1000, 1000) { + + @SuppressLint("DefaultLocale") + @Override + public void onTick(long millisUntilFinished) { + mTvRegisterSmsCall.setText(String.format("%s%s%d%s", + getResources().getString(R.string.register_sms_hint), "(", millisUntilFinished / 1000, ")")); + } + + @Override + public void onFinish() { + mTvRegisterSmsCall.setTag(null); + mTvRegisterSmsCall.setText(getResources().getString(R.string.register_sms_hint)); + mTvRegisterSmsCall.setAlpha(1.0f); + } + }.start(); + String phoneNumber = mEtRegisterUsername.getText().toString().trim(); + OSChinaApi.sendSmsCode(phoneNumber, OSChinaApi.REGISTER_INTENT, mHandler); + } else { + AppContext.showToast(getResources().getString(R.string.register_sms_wait_hint), Toast.LENGTH_SHORT); + } + } + + @Override + public void onFocusChange(View v, boolean hasFocus) { + int id = v.getId(); + switch (id) { + case R.id.et_register_username: + if (hasFocus) { + mLlRegisterPhone.setActivated(true); + mLlRegisterSmsCode.setActivated(false); + } + break; + case R.id.et_register_auth_code: + if (hasFocus) { + mLlRegisterSmsCode.setActivated(true); + mLlRegisterPhone.setActivated(false); + } + break; + default: + break; + } + } + + @Override + public void onGlobalLayout() { + + final ImageView ivLogo = this.mIvLogo; + + Rect keypadRect = new Rect(); + + mLayBackBar.getWindowVisibleDisplayFrame(keypadRect); + + int screenHeight = mLayBackBar.getRootView().getHeight(); + + int keypadHeight = screenHeight - keypadRect.bottom; + if (keypadHeight > 0) { + updateKeyBoardActiveStatus(true); + } else { + updateKeyBoardActiveStatus(false); + } + + if (keypadHeight > 0 && ivLogo.getTag() == null) { + final int height = ivLogo.getHeight(); + final int width = ivLogo.getWidth(); + this.mLogoHeight = height; + this.mLogoWidth = width; + ivLogo.setTag(true); + ValueAnimator valueAnimator = ValueAnimator.ofFloat(1, 0); + valueAnimator.setDuration(400).setInterpolator(new DecelerateInterpolator()); + valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + float animatedValue = (float) animation.getAnimatedValue(); + LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) ivLogo.getLayoutParams(); + + layoutParams.height = (int) (height * animatedValue); + layoutParams.width = (int) (width * animatedValue); + ivLogo.requestLayout(); + ivLogo.setAlpha(animatedValue); + } + }); + + if (valueAnimator.isRunning()) { + valueAnimator.cancel(); + } + valueAnimator.start(); + + + } else if (keypadHeight == 0 && ivLogo.getTag() != null) { + final int height = mLogoHeight; + final int width = mLogoWidth; + ivLogo.setTag(null); + ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1); + valueAnimator.setDuration(400).setInterpolator(new DecelerateInterpolator()); + valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + float animatedValue = (float) animation.getAnimatedValue(); + LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) ivLogo.getLayoutParams(); + layoutParams.height = (int) (height * animatedValue); + layoutParams.width = (int) (width * animatedValue); + ivLogo.requestLayout(); + ivLogo.setAlpha(animatedValue); + } + }); + + if (valueAnimator.isRunning()) { + valueAnimator.cancel(); + } + valueAnimator.start(); + + } + + } +} diff --git a/app/src/main/java/net/oschina/app/improve/account/activity/RegisterStepTwoActivity.java b/app/src/main/java/net/oschina/app/improve/account/activity/RegisterStepTwoActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..c24d917b41c915b38c05fa1ab613f108443db53a --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/account/activity/RegisterStepTwoActivity.java @@ -0,0 +1,417 @@ +package net.oschina.app.improve.account.activity; + +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.Intent; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.View; +import android.view.ViewTreeObserver; +import android.view.animation.DecelerateInterpolator; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.AppContext; +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.account.base.AccountBaseActivity; +import net.oschina.app.improve.account.bean.PhoneToken; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.bean.User; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.util.TDevice; + +import java.lang.reflect.Type; + +import butterknife.Bind; +import butterknife.OnClick; +import cz.msebera.android.httpclient.Header; + +/** + * Created by fei + * on 2016/10/14. + * desc: + */ + +public class RegisterStepTwoActivity extends AccountBaseActivity implements View.OnClickListener, View.OnFocusChangeListener, ViewTreeObserver.OnGlobalLayoutListener { + + public static final String PHONE_TOKEN_KEY = "phoneToken"; + + @Bind(R.id.ly_register_bar) + LinearLayout mLlRegisterBar; + + @Bind(R.id.ll_register_two_username) + LinearLayout mLlRegisterTwoUsername; + @Bind(R.id.et_register_username) + EditText mEtRegisterUsername; + @Bind(R.id.iv_register_username_del) + ImageView mIvRegisterUsernameDel; + @Bind(R.id.ll_register_two_pwd) + LinearLayout mLlRegisterTwoPwd; + @Bind(R.id.et_register_pwd_input) + EditText mEtRegisterPwd; + @Bind(R.id.tv_register_man) + TextView mTvRegisterMan; + @Bind(R.id.tv_register_female) + TextView mTvRegisterFemale; + @Bind(R.id.bt_register_submit) + Button mBtRegisterSubmit; + + private PhoneToken mPhoneToken; + + private TextHttpResponseHandler mHandler = new TextHttpResponseHandler() { + + + @Override + public void onStart() { + super.onStart(); + showWaitDialog(R.string.progress_submit); + } + + @Override + public void onFinish() { + super.onFinish(); + hideWaitDialog(); + } + + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + requestFailureHint(throwable); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + + + Type type = new TypeToken>() { + }.getType(); + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, type); + + if (resultBean.isSuccess()) { + User user = resultBean.getResult(); + AccountHelper.login(user, headers); + AppContext.showToast(getResources().getString(R.string.register_success_hint), Toast.LENGTH_SHORT); + sendLocalReceiver(); + finish(); + } else { + int code = resultBean.getCode(); + switch (code) { + case 216: + //phoneToken 已经失效 + finish(); + break; + case 217: + mLlRegisterTwoUsername.setBackgroundResource(R.drawable.bg_login_input_error); + break; + case 218: + finish(); + break; + case 219: + mLlRegisterTwoPwd.setBackgroundResource(R.drawable.bg_login_input_error); + break; + default: + break; + } + showToastForKeyBord(resultBean.getMessage()); + } + + } + }; + private int mTopMargin; + + /** + * show register step two activity + * + * @param context context + */ + public static void show(Context context, PhoneToken phoneToken) { + Intent intent = new Intent(context, RegisterStepTwoActivity.class); + intent.putExtra(PHONE_TOKEN_KEY, phoneToken); + context.startActivity(intent); + } + + @Override + protected int getContentView() { + return R.layout.activity_main_register_step_two; + } + + @Override + protected void initWidget() { + super.initWidget(); + + TextView tvLabel = (TextView) mLlRegisterBar.findViewById(R.id.tv_navigation_label); + tvLabel.setText(R.string.login_register_hint); + + mEtRegisterUsername.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @SuppressWarnings("deprecation") + @Override + public void afterTextChanged(Editable s) { + int length = s.length(); + + String smsCode = mEtRegisterPwd.getText().toString().trim(); + + if (!TextUtils.isEmpty(smsCode)) { + mBtRegisterSubmit.setBackgroundResource(R.drawable.bg_login_submit); + mBtRegisterSubmit.setTextColor(getResources().getColor(R.color.white)); + } else { + mBtRegisterSubmit.setBackgroundResource(R.drawable.bg_login_submit_lock); + mBtRegisterSubmit.setTextColor(getResources().getColor(R.color.account_lock_font_color)); + } + + if (length > 0) { + mIvRegisterUsernameDel.setVisibility(View.VISIBLE); + } else { + mIvRegisterUsernameDel.setVisibility(View.INVISIBLE); + } + + if (length > 12) { + showToastForKeyBord(R.string.register_username_error); + mLlRegisterTwoUsername.setBackgroundResource(R.drawable.bg_login_input_error); + } else { + mLlRegisterTwoUsername.setBackgroundResource(R.drawable.bg_login_input_ok); + } + } + }); + mEtRegisterUsername.setOnFocusChangeListener(this); + mEtRegisterPwd.setOnFocusChangeListener(this); + mEtRegisterPwd.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @SuppressWarnings("deprecation") + @Override + public void afterTextChanged(Editable s) { + int length = s.length(); + if (length < 6) { + mLlRegisterTwoPwd.setBackgroundResource(R.drawable.bg_login_input_error); + } else { + mLlRegisterTwoPwd.setBackgroundResource(R.drawable.bg_login_input_ok); + } + String username = mEtRegisterUsername.getText().toString().trim(); + if (!TextUtils.isEmpty(username)) { + mBtRegisterSubmit.setBackgroundResource(R.drawable.bg_login_submit); + mBtRegisterSubmit.setTextColor(getResources().getColor(R.color.white)); + } else { + mBtRegisterSubmit.setBackgroundResource(R.drawable.bg_login_submit_lock); + mBtRegisterSubmit.setTextColor(getResources().getColor(R.color.account_lock_font_color)); + } + } + }); + } + + @Override + protected void initData() { + super.initData();//必须要调用,用来注册本地广播 + Intent intent = getIntent(); + mPhoneToken = (PhoneToken) intent.getSerializableExtra(PHONE_TOKEN_KEY); + } + + @Override + protected void onResume() { + super.onResume(); + mLlRegisterBar.getViewTreeObserver().addOnGlobalLayoutListener(this); + } + + @SuppressWarnings("ConstantConditions") + @Override + protected void onDestroy() { + super.onDestroy(); + hideKeyBoard(getCurrentFocus().getWindowToken()); + mLlRegisterBar.getViewTreeObserver().removeOnGlobalLayoutListener(this); + } + + @SuppressWarnings({"deprecation", "ConstantConditions"}) + @OnClick({R.id.ib_navigation_back, R.id.iv_register_username_del, R.id.tv_register_man, + R.id.tv_register_female, R.id.bt_register_submit, R.id.lay_register_two_container}) + @Override + public void onClick(View v) { + int id = v.getId(); + switch (id) { + case R.id.ib_navigation_back: + finish(); + break; + case R.id.iv_register_username_del: + mEtRegisterUsername.setText(null); + break; + case R.id.tv_register_man: + if (mTvRegisterMan.getTag() != null) { + Drawable left = getResources().getDrawable(R.mipmap.btn_gender_male_normal); + mTvRegisterMan.setCompoundDrawablesWithIntrinsicBounds(left, null, null, null); + mTvRegisterMan.setTag(null); + } else { + Drawable left = getResources().getDrawable(R.mipmap.btn_gender_male_actived); + mTvRegisterMan.setCompoundDrawablesWithIntrinsicBounds(left, null, null, null); + mTvRegisterMan.setTag(false); + Drawable female = getResources().getDrawable(R.mipmap.btn_gender_female_normal); + mTvRegisterFemale.setCompoundDrawablesWithIntrinsicBounds(female, null, null, null); + mTvRegisterFemale.setTag(null); + } + + break; + case R.id.tv_register_female: + if (mTvRegisterFemale.getTag() != null) { + Drawable left = getResources().getDrawable(R.mipmap.btn_gender_female_normal); + mTvRegisterFemale.setCompoundDrawablesWithIntrinsicBounds(left, null, null, null); + mTvRegisterFemale.setTag(null); + } else { + Drawable left = getResources().getDrawable(R.mipmap.btn_gender_female_actived); + mTvRegisterFemale.setCompoundDrawablesWithIntrinsicBounds(left, null, null, null); + mTvRegisterFemale.setTag(true); + + Drawable men = getResources().getDrawable(R.mipmap.btn_gender_male_normal); + mTvRegisterMan.setCompoundDrawablesWithIntrinsicBounds(men, null, null, null); + mTvRegisterMan.setTag(null); + } + break; + case R.id.bt_register_submit: + requestRegisterUserInfo(); + break; + case R.id.lay_register_two_container: + hideKeyBoard(getCurrentFocus().getWindowToken()); + break; + default: + break; + } + + } + + private void requestRegisterUserInfo() { + + String username = mEtRegisterUsername.getText().toString().trim(); + String pwd = mEtRegisterPwd.getText().toString().trim(); + + if (TextUtils.isEmpty(username) || TextUtils.isEmpty(pwd)) { + return; + } + + if (!TDevice.hasInternet()) { + showToastForKeyBord(R.string.tip_network_error); + return; + } + + int gender = 0; + + Object isMan = mTvRegisterMan.getTag(); + if (isMan != null) { + gender = 1; + } + + Object isFemale = mTvRegisterFemale.getTag(); + if (isFemale != null) { + gender = 2; + } + + OSChinaApi.register(username, getSha1(pwd), gender, mPhoneToken.getToken(), mHandler); + } + + @Override + public void onFocusChange(View v, boolean hasFocus) { + + int id = v.getId(); + switch (id) { + case R.id.et_register_username: + if (hasFocus) { + mLlRegisterTwoUsername.setActivated(true); + mLlRegisterTwoPwd.setActivated(false); + } + break; + case R.id.et_register_pwd_input: + if (hasFocus) { + mLlRegisterTwoPwd.setActivated(true); + mLlRegisterTwoUsername.setActivated(false); + } + break; + default: + break; + } + + } + + @Override + public void onGlobalLayout() { + + final LinearLayout layRegisterTwoUsername = this.mLlRegisterTwoUsername; + Rect keypadRect = new Rect(); + + mLlRegisterBar.getWindowVisibleDisplayFrame(keypadRect); + + int screenHeight = mLlRegisterBar.getRootView().getHeight(); + int keypadHeight = screenHeight - keypadRect.bottom; + + if (keypadHeight > 0) { + updateKeyBoardActiveStatus(true); + } else { + updateKeyBoardActiveStatus(false); + } + + if (keypadHeight > 0 && layRegisterTwoUsername.getTag() == null) { + final LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) layRegisterTwoUsername.getLayoutParams(); + final int topMargin = layoutParams.topMargin; + this.mTopMargin = topMargin; + layRegisterTwoUsername.setTag(true); + ValueAnimator valueAnimator = ValueAnimator.ofFloat(1, 0); + valueAnimator.setDuration(400).setInterpolator(new DecelerateInterpolator()); + valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + float animatedValue = (float) animation.getAnimatedValue(); + layoutParams.topMargin = (int) (topMargin * animatedValue); + layRegisterTwoUsername.requestLayout(); + } + }); + + if (valueAnimator.isRunning()) { + valueAnimator.cancel(); + } + valueAnimator.start(); + + } else if (keypadHeight == 0 && layRegisterTwoUsername.getTag() != null) { + final int topMargin = mTopMargin; + final LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) layRegisterTwoUsername.getLayoutParams(); + layRegisterTwoUsername.setTag(null); + ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1); + valueAnimator.setDuration(400).setInterpolator(new DecelerateInterpolator()); + valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + float animatedValue = (float) animation.getAnimatedValue(); + layoutParams.topMargin = (int) (topMargin * animatedValue); + layRegisterTwoUsername.requestLayout(); + } + }); + if (valueAnimator.isRunning()) { + valueAnimator.cancel(); + } + valueAnimator.start(); + + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/account/activity/ResetPwdActivity.java b/app/src/main/java/net/oschina/app/improve/account/activity/ResetPwdActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..b9a42a45f9dfaa065fe81689a48e1676c8f3126a --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/account/activity/ResetPwdActivity.java @@ -0,0 +1,300 @@ +package net.oschina.app.improve.account.activity; + +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.Intent; +import android.graphics.Rect; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.View; +import android.view.ViewTreeObserver; +import android.view.animation.DecelerateInterpolator; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.AppContext; +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.account.base.AccountBaseActivity; +import net.oschina.app.improve.account.bean.PhoneToken; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.util.TDevice; + +import java.lang.reflect.Type; + +import butterknife.Bind; +import butterknife.OnClick; +import cz.msebera.android.httpclient.Header; + +/** + * Created by fei + * on 2016/10/14. + * desc: + */ + +public class ResetPwdActivity extends AccountBaseActivity implements View.OnClickListener, View.OnFocusChangeListener, + ViewTreeObserver.OnGlobalLayoutListener { + + @Bind(R.id.ly_reset_bar) + LinearLayout mLlResetBar; + + @Bind(R.id.ll_reset_pwd) + LinearLayout mLlResetPwd; + @Bind(R.id.et_reset_pwd) + EditText mEtResetPwd; + @Bind(R.id.iv_reset_pwd_del) + ImageView mIvResetPwdDel; + @Bind(R.id.bt_reset_submit) + Button mBtResetSubmit; + private PhoneToken mPhoneToken; + private TextHttpResponseHandler mHandler = new TextHttpResponseHandler() { + + @Override + public void onStart() { + super.onStart(); + showWaitDialog(R.string.progress_submit); + } + + @Override + public void onFinish() { + super.onFinish(); + hideWaitDialog(); + } + + @Override + public void onCancel() { + super.onCancel(); + hideWaitDialog(); + } + + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + requestFailureHint(throwable); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + + Type type = new TypeToken() { + }.getType(); + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, type); + int code = resultBean.getCode(); + + switch (code) { + case 1: + AppContext.showToast(getResources().getString(R.string.reset_success_hint), Toast.LENGTH_SHORT); + LoginActivity.show(ResetPwdActivity.this); + finish(); + break; + case 216: + showToastForKeyBord(resultBean.getMessage()); + finish(); + break; + case 219: + mLlResetPwd.setBackgroundResource(R.drawable.bg_login_input_error); + showToastForKeyBord(resultBean.getMessage()); + break; + default: + break; + } + } + }; + private int mTopMargin; + + /** + * show the resetPwdActivity + * + * @param context context + */ + public static void show(Context context, PhoneToken phoneToken) { + Intent intent = new Intent(context, ResetPwdActivity.class); + intent.putExtra(RegisterStepTwoActivity.PHONE_TOKEN_KEY, phoneToken); + context.startActivity(intent); + } + + @Override + protected int getContentView() { + return R.layout.activity_main_reset_pwd; + } + + @Override + protected void initWidget() { + super.initWidget(); + TextView tvLabel = (TextView) mLlResetBar.findViewById(R.id.tv_navigation_label); + tvLabel.setText(R.string.reset_pwd_label); + mEtResetPwd.setOnFocusChangeListener(this); + mEtResetPwd.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @SuppressWarnings("deprecation") + @Override + public void afterTextChanged(Editable s) { + int length = s.length(); + if (length >= 6) { + mIvResetPwdDel.setVisibility(View.VISIBLE); + mLlResetPwd.setBackgroundResource(R.drawable.bg_login_input_ok); + mBtResetSubmit.setBackgroundResource(R.drawable.bg_login_submit); + mBtResetSubmit.setTextColor(getResources().getColor(R.color.white)); + } else { + if (length <= 0) { + mIvResetPwdDel.setVisibility(View.GONE); + mLlResetPwd.setBackgroundResource(R.drawable.bg_login_input_ok); + } else { + mIvResetPwdDel.setVisibility(View.VISIBLE); + mLlResetPwd.setBackgroundResource(R.drawable.bg_login_input_error); + } + mBtResetSubmit.setBackgroundResource(R.drawable.bg_login_submit_lock); + mBtResetSubmit.setTextColor(getResources().getColor(R.color.account_lock_font_color)); + } + + } + }); + } + + @Override + protected void initData() { + super.initData();//必须要调用,用来注册本地广播 + Intent intent = getIntent(); + mPhoneToken = (PhoneToken) intent.getSerializableExtra(RegisterStepTwoActivity.PHONE_TOKEN_KEY); + } + + @Override + protected void onResume() { + super.onResume(); + mLlResetBar.getViewTreeObserver().addOnGlobalLayoutListener(this); + } + + @SuppressWarnings("ConstantConditions") + @Override + protected void onDestroy() { + super.onDestroy(); + hideKeyBoard(getCurrentFocus().getWindowToken()); + mLlResetBar.getViewTreeObserver().removeOnGlobalLayoutListener(this); + } + + + @SuppressWarnings("ConstantConditions") + @OnClick({R.id.ib_navigation_back, R.id.iv_reset_pwd_del, R.id.bt_reset_submit, R.id.lay_reset_container}) + @Override + public void onClick(View v) { + int id = v.getId(); + switch (id) { + case R.id.ib_navigation_back: + finish(); + break; + case R.id.iv_reset_pwd_del: + mEtResetPwd.setText(null); + break; + case R.id.bt_reset_submit: + requestResetPwd(); + break; + case R.id.lay_reset_container: + hideKeyBoard(getCurrentFocus().getWindowToken()); + break; + default: + break; + } + + } + + private void requestResetPwd() { + String tempPwd = mEtResetPwd.getText().toString().trim(); + if (TextUtils.isEmpty(tempPwd) || tempPwd.length() < 6) { + //showToastForKeyBord(R.string.reset_pwd_hint); + return; + } + if (!TDevice.hasInternet()) { + showToastForKeyBord(R.string.tip_network_error); + return; + } + + OSChinaApi.resetPwd(getSha1(tempPwd), mPhoneToken.getToken(), mHandler); + } + + + @Override + public void onFocusChange(View v, boolean hasFocus) { + if (hasFocus) { + mLlResetPwd.setActivated(true); + } + } + + @Override + public void onGlobalLayout() { + + final LinearLayout kayResetPwd = this.mLlResetPwd; + Rect keypadRect = new Rect(); + + mLlResetBar.getWindowVisibleDisplayFrame(keypadRect); + + int screenHeight = mLlResetBar.getRootView().getHeight(); + + int keypadHeight = screenHeight - keypadRect.bottom; + + if (keypadHeight > 0) { + updateKeyBoardActiveStatus(true); + } else { + updateKeyBoardActiveStatus(false); + } + + if (keypadHeight > 0 && kayResetPwd.getTag() == null) { + final LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) kayResetPwd.getLayoutParams(); + final int topMargin = layoutParams.topMargin; + this.mTopMargin = topMargin; + kayResetPwd.setTag(true); + ValueAnimator valueAnimator = ValueAnimator.ofFloat(1, 0); + valueAnimator.setDuration(400).setInterpolator(new DecelerateInterpolator()); + valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + float animatedValue = (float) animation.getAnimatedValue(); + layoutParams.topMargin = (int) (topMargin * animatedValue); + kayResetPwd.requestLayout(); + } + }); + + if (valueAnimator.isRunning()) { + valueAnimator.cancel(); + } + valueAnimator.start(); + + + } else if (keypadHeight == 0 && kayResetPwd.getTag() != null) { + final int topMargin = mTopMargin; + final LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) kayResetPwd.getLayoutParams(); + kayResetPwd.setTag(null); + ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1); + valueAnimator.setDuration(400).setInterpolator(new DecelerateInterpolator()); + valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + float animatedValue = (float) animation.getAnimatedValue(); + layoutParams.topMargin = (int) (topMargin * animatedValue); + kayResetPwd.requestLayout(); + } + }); + if (valueAnimator.isRunning()) { + valueAnimator.cancel(); + } + valueAnimator.start(); + + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/account/activity/RetrieveActivity.java b/app/src/main/java/net/oschina/app/improve/account/activity/RetrieveActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..b2256257082bbc3e60fe403b3588f8d3a1827f02 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/account/activity/RetrieveActivity.java @@ -0,0 +1,504 @@ +package net.oschina.app.improve.account.activity; + +import android.animation.ValueAnimator; +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.Intent; +import android.graphics.Rect; +import android.net.Uri; +import android.os.CountDownTimer; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.View; +import android.view.ViewTreeObserver; +import android.view.animation.DecelerateInterpolator; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.AppContext; +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.account.base.AccountBaseActivity; +import net.oschina.app.improve.account.bean.PhoneToken; +import net.oschina.app.improve.account.constants.UserConstants; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.utils.AssimilateUtils; +import net.oschina.app.util.TDevice; + +import java.lang.reflect.Type; + +import butterknife.Bind; +import butterknife.OnClick; +import cz.msebera.android.httpclient.Header; + +/** + * Created by fei + * on 2016/10/14. + * desc: + */ + +public class RetrieveActivity extends AccountBaseActivity implements View.OnClickListener, View.OnFocusChangeListener, + ViewTreeObserver.OnGlobalLayoutListener { + + @Bind(R.id.ly_retrieve_bar) + LinearLayout mLlRetrieveBar; + + @Bind(R.id.ll_retrieve_tel) + LinearLayout mLlRetrieveTel; + @Bind(R.id.et_retrieve_tel) + EditText mEtRetrieveTel; + @Bind(R.id.iv_retrieve_tel_del) + ImageView mIvRetrieveTelDel; + + @Bind(R.id.ll_retrieve_code) + LinearLayout mLlRetrieveCode; + @Bind(R.id.et_retrieve_code_input) + EditText mEtRetrieveCodeInput; + @Bind(R.id.retrieve_sms_call) + TextView mTvRetrieveSmsCall; + + @Bind(R.id.bt_retrieve_submit) + Button mBtRetrieveSubmit; + @Bind(R.id.tv_retrieve_label) + TextView mTvRetrieveLabel; + private boolean mMachPhoneNum; + + private CountDownTimer mTimer; + + private int mRequestType; + private TextHttpResponseHandler mHandler = new TextHttpResponseHandler() { + + @Override + public void onStart() { + super.onStart(); + showWaitDialog(R.string.progress_submit); + } + + @Override + public void onFinish() { + super.onFinish(); + hideWaitDialog(); + } + + @Override + public void onCancel() { + super.onCancel(); + hideWaitDialog(); + } + + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + //请求失败,比如服务器连接超时,回收timer,需重新请求发送验证码 + if (mRequestType == 1) { + if (mTimer != null) { + mTimer.onFinish(); + mTimer.cancel(); + } + } + requestFailureHint(throwable); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + + try { + switch (mRequestType) { + //第一步请求发送验证码 + case 1: + Type type = new TypeToken() { + }.getType(); + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, type); + int code = resultBean.getCode(); + switch (code) { + case 1: + //发送验证码成功,请求进入下一步 + //mRequestType = 2; + mEtRetrieveCodeInput.setText(null); + AppContext.showToast(R.string.send_sms_code_success_hint, Toast.LENGTH_SHORT); + break; + case 218: + //手机号已被注册,提示重新输入 + mLlRetrieveTel.setBackgroundResource(R.drawable.bg_login_input_error); + showToastForKeyBord(resultBean.getMessage()); + break; + case 0: + //异常错误,发送验证码失败,回收timer,需重新请求发送验证码 + if (mTimer != null) { + mTimer.onFinish(); + mTimer.cancel(); + } + showToastForKeyBord(resultBean.getMessage()); + break; + default: + break; + } + + break; + //第二步请求进行重置密码 + case 2: + + Type phoneType = new TypeToken>() { + }.getType(); + + ResultBean phoneTokenResultBean = AppOperator.createGson().fromJson(responseString, phoneType); + + int smsCode = phoneTokenResultBean.getCode(); + switch (smsCode) { + case 1: + if (phoneTokenResultBean.isSuccess()) { + PhoneToken phoneToken = phoneTokenResultBean.getResult(); + if (phoneToken != null) { + if (mTimer != null) { + mTimer.onFinish(); + mTimer.cancel(); + } + ResetPwdActivity.show(RetrieveActivity.this, phoneToken); + } + } else { + showToastForKeyBord(phoneTokenResultBean.getMessage()); + } + break; + case 215: + mLlRetrieveCode.setBackgroundResource(R.drawable.bg_login_input_error); + showToastForKeyBord(phoneTokenResultBean.getMessage()); + break; + default: + break; + } + break; + default: + break; + } + + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + + } + }; + private int mTopMargin; + + /** + * show the retrieve activity + * + * @param context context + */ + public static void show(Context context) { + Intent intent = new Intent(context, RetrieveActivity.class); + context.startActivity(intent); + } + + @Override + protected int getContentView() { + return R.layout.activity_main_retrieve_pwd; + } + + @Override + protected void initWidget() { + super.initWidget(); + + TextView tvLabel = (TextView) mLlRetrieveBar.findViewById(R.id.tv_navigation_label); + tvLabel.setText(R.string.retrieve_pwd_label); + mEtRetrieveTel.setOnFocusChangeListener(this); + mEtRetrieveTel.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + int length = s.length(); + if (length > 0) { + mIvRetrieveTelDel.setVisibility(View.VISIBLE); + } else { + mIvRetrieveTelDel.setVisibility(View.INVISIBLE); + } + + } + + @SuppressWarnings("deprecation") + @Override + public void afterTextChanged(Editable s) { + int length = s.length(); + String input = s.toString(); + mMachPhoneNum = AssimilateUtils.machPhoneNum(input); + + //对提交控件的状态判定 + if (mMachPhoneNum) { + String smsCode = mEtRetrieveCodeInput.getText().toString().trim(); + + if (!TextUtils.isEmpty(smsCode)) { + mBtRetrieveSubmit.setBackgroundResource(R.drawable.bg_login_submit); + mBtRetrieveSubmit.setTextColor(getResources().getColor(R.color.white)); + } else { + mBtRetrieveSubmit.setBackgroundResource(R.drawable.bg_login_submit_lock); + mBtRetrieveSubmit.setTextColor(getResources().getColor(R.color.account_lock_font_color)); + } + } else { + mBtRetrieveSubmit.setBackgroundResource(R.drawable.bg_login_submit_lock); + mBtRetrieveSubmit.setTextColor(getResources().getColor(R.color.account_lock_font_color)); + } + + if (length > 0 && length < 11) { + mLlRetrieveTel.setBackgroundResource(R.drawable.bg_login_input_error); + mTvRetrieveSmsCall.setAlpha(0.4f); + } else if (length == 11) { + if (mMachPhoneNum) { + mLlRetrieveTel.setBackgroundResource(R.drawable.bg_login_input_ok); + if (mTvRetrieveSmsCall.getTag() == null) { + mTvRetrieveSmsCall.setAlpha(1.0f); + } else { + mTvRetrieveSmsCall.setAlpha(0.4f); + } + } else { + mLlRetrieveTel.setBackgroundResource(R.drawable.bg_login_input_error); + showToastForKeyBord(R.string.hint_username_ok); + mTvRetrieveSmsCall.setAlpha(0.4f); + } + } else if (length > 11) { + mTvRetrieveSmsCall.setAlpha(0.4f); + mLlRetrieveTel.setBackgroundResource(R.drawable.bg_login_input_error); + } else if (length <= 0) { + mTvRetrieveSmsCall.setAlpha(0.4f); + mLlRetrieveTel.setBackgroundResource(R.drawable.bg_login_input_ok); + } + + } + }); + mEtRetrieveCodeInput.setOnFocusChangeListener(this); + mEtRetrieveCodeInput.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @SuppressWarnings("deprecation") + @Override + public void afterTextChanged(Editable s) { + int length = s.length(); + if (length > 0 && mMachPhoneNum) { + mBtRetrieveSubmit.setBackgroundResource(R.drawable.bg_login_submit); + mBtRetrieveSubmit.setTextColor(getResources().getColor(R.color.white)); + } else { + mBtRetrieveSubmit.setBackgroundResource(R.drawable.bg_login_submit_lock); + mBtRetrieveSubmit.setTextColor(getResources().getColor(R.color.account_lock_font_color)); + } + mLlRetrieveCode.setBackgroundResource(R.drawable.bg_login_input_ok); + } + }); + } + + @Override + protected void initData() { + super.initData();//必须要调用,用来注册本地广播 + } + + @Override + protected void onResume() { + super.onResume(); + mLlRetrieveBar.getViewTreeObserver().addOnGlobalLayoutListener(this); + } + + @SuppressWarnings("ConstantConditions") + @Override + protected void onDestroy() { + super.onDestroy(); + hideKeyBoard(getCurrentFocus().getWindowToken()); + mLlRetrieveBar.getViewTreeObserver().removeOnGlobalLayoutListener(this); + } + + @SuppressWarnings("ConstantConditions") + @OnClick({R.id.ib_navigation_back, R.id.iv_retrieve_tel_del, R.id.retrieve_sms_call, + R.id.bt_retrieve_submit, R.id.tv_retrieve_label, R.id.lay_retrieve_container}) + @Override + public void onClick(View v) { + int id = v.getId(); + switch (id) { + case R.id.ib_navigation_back: + finish(); + break; + case R.id.iv_retrieve_tel_del: + mEtRetrieveTel.setText(null); + break; + case R.id.retrieve_sms_call: + //获取验证码 + requestSmsCode(); + + break; + case R.id.bt_retrieve_submit: + //根据验证码获取phoneToken + requestRetrievePwd(); + break; + case R.id.tv_retrieve_label: + + //打开web进入邮箱找回密码 + + Intent intent = new Intent(); + intent.setAction(Intent.ACTION_VIEW); + // intent.setAction(Intent.CATEGORY_BROWSABLE); + Uri content_url = Uri.parse(UserConstants.RETRIEVE_PWD_URL); + intent.setData(content_url); + startActivity(intent); + break; + case R.id.lay_retrieve_container: + hideKeyBoard(getCurrentFocus().getWindowToken()); + break; + default: + break; + } + + } + + private void requestRetrievePwd() { + + String smsCode = mEtRetrieveCodeInput.getText().toString().trim(); + if (!mMachPhoneNum || TextUtils.isEmpty(smsCode)) { + // showToastForKeyBord(R.string.hint_username_ok); + return; + } + + if (!TDevice.hasInternet()) { + showToastForKeyBord(R.string.tip_network_error); + return; + } + mRequestType = 2; + String phoneNumber = mEtRetrieveTel.getText().toString().trim(); + OSChinaApi.validateRegisterInfo(phoneNumber, smsCode, mHandler); + } + + private void requestSmsCode() { + if (!mMachPhoneNum) { + //showToastForKeyBord(R.string.hint_username_ok); + return; + } + + if (!TDevice.hasInternet()) { + showToastForKeyBord(R.string.tip_network_error); + return; + } + + if (mTvRetrieveSmsCall.getTag() == null) { + mRequestType = 1; + mTvRetrieveSmsCall.setAlpha(0.6f); + mTvRetrieveSmsCall.setTag(true); + mTimer = new CountDownTimer(60 * 1000, 1000) { + + @SuppressLint("DefaultLocale") + @Override + public void onTick(long millisUntilFinished) { + mTvRetrieveSmsCall.setText(String.format("%s%s%d%s", + getResources().getString(R.string.register_sms_hint), "(", millisUntilFinished / 1000, ")")); + } + + @Override + public void onFinish() { + mTvRetrieveSmsCall.setTag(null); + mTvRetrieveSmsCall.setText(getResources().getString(R.string.register_sms_hint)); + mTvRetrieveSmsCall.setAlpha(1.0f); + } + }.start(); + String phoneNumber = mEtRetrieveTel.getText().toString().trim(); + OSChinaApi.sendSmsCode(phoneNumber, OSChinaApi.RESET_PWD_INTENT, mHandler); + } else { + AppContext.showToast(getResources().getString(R.string.register_sms_wait_hint), Toast.LENGTH_SHORT); + } + } + + @Override + public void onFocusChange(View v, boolean hasFocus) { + int id = v.getId(); + switch (id) { + case R.id.et_retrieve_tel: + if (hasFocus) { + mLlRetrieveTel.setActivated(true); + mLlRetrieveCode.setActivated(false); + } + break; + case R.id.et_retrieve_code_input: + if (hasFocus) { + mLlRetrieveCode.setActivated(true); + mLlRetrieveTel.setActivated(false); + } + break; + default: + break; + } + } + + @Override + public void onGlobalLayout() { + + final LinearLayout layRetrieveTel = this.mLlRetrieveTel; + Rect KeypadRect = new Rect(); + + mLlRetrieveBar.getWindowVisibleDisplayFrame(KeypadRect); + + int screenHeight = mLlRetrieveBar.getRootView().getHeight(); + + int keypadHeight = screenHeight - KeypadRect.bottom; + + if (keypadHeight > 0) { + updateKeyBoardActiveStatus(true); + } else { + updateKeyBoardActiveStatus(false); + } + + if (keypadHeight > 0 && layRetrieveTel.getTag() == null) { + final LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) layRetrieveTel.getLayoutParams(); + final int topMargin = layoutParams.topMargin; + this.mTopMargin = topMargin; + layRetrieveTel.setTag(true); + ValueAnimator valueAnimator = ValueAnimator.ofFloat(1, 0); + valueAnimator.setDuration(400).setInterpolator(new DecelerateInterpolator()); + valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + float animatedValue = (float) animation.getAnimatedValue(); + layoutParams.topMargin = (int) (topMargin * animatedValue); + layRetrieveTel.requestLayout(); + } + }); + + if (valueAnimator.isRunning()) { + valueAnimator.cancel(); + } + valueAnimator.start(); + + + } else if (keypadHeight == 0 && layRetrieveTel.getTag() != null) { + final int topMargin = mTopMargin; + final LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) layRetrieveTel.getLayoutParams(); + layRetrieveTel.setTag(null); + ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1); + valueAnimator.setDuration(400).setInterpolator(new DecelerateInterpolator()); + valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + float animatedValue = (float) animation.getAnimatedValue(); + layoutParams.topMargin = (int) (topMargin * animatedValue); + layRetrieveTel.requestLayout(); + } + }); + if (valueAnimator.isRunning()) { + valueAnimator.cancel(); + } + valueAnimator.start(); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/account/base/AccountBaseActivity.java b/app/src/main/java/net/oschina/app/improve/account/base/AccountBaseActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..8cd04464a56de9a23f423deae5e8e3733f3b9270 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/account/base/AccountBaseActivity.java @@ -0,0 +1,293 @@ +package net.oschina.app.improve.account.base; + +import android.annotation.SuppressLint; +import android.app.ProgressDialog; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.IBinder; +import android.support.annotation.NonNull; +import android.support.annotation.StringRes; +import android.support.v4.content.LocalBroadcastManager; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.inputmethod.InputMethodManager; +import android.widget.TextView; +import android.widget.Toast; + +import net.oschina.app.R; +import net.oschina.app.improve.base.activities.BaseActivity; +import net.oschina.app.improve.utils.DialogHelper; + +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * Created by fei + * on 2016/10/31. + * desc: + */ + +public class AccountBaseActivity extends BaseActivity { + + private ProgressDialog mDialog; + public static final String ACTION_ACCOUNT_FINISH_ALL = "app.oschina.net.action.finish.all"; + protected LocalBroadcastManager mManager; + private BroadcastReceiver mReceiver; + protected InputMethodManager mInputMethodManager; + protected Toast mToast; + private boolean mKeyBoardIsActive; + + @Override + protected int getContentView() { + return 0; + } + + @Override + protected void initData() { + super.initData(); + registerLocalReceiver(); + mInputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); + } + + @Override + public void onBackPressed() { + super.onBackPressed(); + finish(); + } + + @Override + protected void onStop() { + super.onStop(); + hideWaitDialog(); + } + + @SuppressWarnings("ConstantConditions") + @Override + protected void onDestroy() { + super.onDestroy(); + hideKeyBoard(getCurrentFocus().getWindowToken()); + if (mManager != null) { + if (mReceiver != null) + mManager.unregisterReceiver(mReceiver); + } + } + + /** + * showToast + * + * @param text text + */ + @SuppressLint("InflateParams") + private void showToast(String text) { + Toast toast = this.mToast; + if (toast == null) { + toast = initToast(); + } + View rootView = LayoutInflater.from(this).inflate(R.layout.view_toast, null, false); + TextView textView = (TextView) rootView.findViewById(R.id.title_tv); + textView.setText(text); + toast.setView(rootView); + initToastGravity(toast); + toast.show(); + } + + /** + * showToast + * + * @param id id + */ + @SuppressLint("InflateParams") + private void showToast(@StringRes int id) { + Toast toast = this.mToast; + if (toast == null) { + toast = initToast(); + } + View rootView = LayoutInflater.from(this).inflate(R.layout.view_toast, null, false); + TextView textView = (TextView) rootView.findViewById(R.id.title_tv); + textView.setText(id); + toast.setView(rootView); + initToastGravity(toast); + toast.show(); + } + + @NonNull + private Toast initToast() { + Toast toast; + toast = new Toast(this); + toast.setDuration(Toast.LENGTH_SHORT); + this.mToast = toast; + return toast; + } + + private void initToastGravity(Toast toast) { + boolean isCenter = this.mKeyBoardIsActive; + if (isCenter) { + toast.setGravity(Gravity.CENTER_HORIZONTAL, 0, 0); + } else { + toast.setGravity(Gravity.BOTTOM, 0, getResources().getDimensionPixelSize(R.dimen.toast_y_offset)); + } + } + + /** + * update keyBord active status + * + * @param isActive isActive + */ + protected void updateKeyBoardActiveStatus(boolean isActive) { + this.mKeyBoardIsActive = isActive; + } + + /** + * cancelToast + */ + protected void cancelToast() { + if (mToast != null) { + mToast.cancel(); + } + } + + protected boolean sendLocalReceiver() { + if (mManager != null) { + Intent intent = new Intent(); + intent.setAction(ACTION_ACCOUNT_FINISH_ALL); + return mManager.sendBroadcast(intent); + } + + return false; + } + + /** + * register localReceiver + */ + private void registerLocalReceiver() { + if (mManager == null) + mManager = LocalBroadcastManager.getInstance(this); + IntentFilter filter = new IntentFilter(); + filter.addAction(ACTION_ACCOUNT_FINISH_ALL); + if (mReceiver == null) + mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (ACTION_ACCOUNT_FINISH_ALL.equals(action)) { + finish(); + } + } + }; + mManager.registerReceiver(mReceiver, filter); + } + + /** + * show WaitDialog + * + * @return progressDialog + */ + protected ProgressDialog showWaitDialog(@StringRes int messageId) { + if (mDialog == null) { + if (messageId <= 0) { + mDialog = DialogHelper.getProgressDialog(this, true); + } else { + String message = getResources().getString(messageId); + mDialog = DialogHelper.getProgressDialog(this, message, true); + } + } + mDialog.show(); + + return mDialog; + } + + /** + * show FocusWaitDialog + * + * @return progressDialog + */ + protected ProgressDialog showFocusWaitDialog() { + + String message = getResources().getString(R.string.progress_submit); + if (mDialog == null) { + mDialog = DialogHelper.getProgressDialog(this, message, false);//DialogHelp.getWaitDialog(this, message); + } + mDialog.show(); + + return mDialog; + } + + /** + * hide waitDialog + */ + protected void hideWaitDialog() { + ProgressDialog dialog = mDialog; + if (dialog != null) { + mDialog = null; + try { + dialog.cancel(); + // dialog.dismiss(); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + } + + protected void showToastForKeyBord(@StringRes int id) { + showToast(id); + } + + protected void showToastForKeyBord(String message) { + showToast(message); + } + + protected void hideKeyBoard(IBinder windowToken) { + InputMethodManager inputMethodManager = this.mInputMethodManager; + if (inputMethodManager == null) return; + boolean active = inputMethodManager.isActive(); + if (active) { + inputMethodManager.hideSoftInputFromWindow(windowToken, 0); + } + } + + /** + * request network error + * + * @param throwable throwable + */ + protected void requestFailureHint(Throwable throwable) { + if (throwable != null) { + throwable.printStackTrace(); + } + showToastForKeyBord(R.string.request_error_hint); + } + + /** + * sha-1 to hex + * + * @param tempPwd tempPwd + * @return sha-1 pwd + */ + @NonNull + protected String getSha1(String tempPwd) { + try { + MessageDigest messageDigest = MessageDigest.getInstance("SHA-1"); + messageDigest.update(tempPwd.getBytes("utf-8")); + byte[] bytes = messageDigest.digest(); + + StringBuilder tempHex = new StringBuilder(); + // 字节数组转换为 十六进制数 + for (byte aByte : bytes) { + String shaHex = Integer.toHexString(aByte & 0xff); + if (shaHex.length() < 2) { + tempHex.append(0); + } + tempHex.append(shaHex); + } + return tempHex.toString(); + } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) { + e.printStackTrace(); + } + + return tempPwd; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/account/bean/PhoneToken.java b/app/src/main/java/net/oschina/app/improve/account/bean/PhoneToken.java new file mode 100644 index 0000000000000000000000000000000000000000..d853ffe529d7b9a280d2c309157387ba777e2a47 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/account/bean/PhoneToken.java @@ -0,0 +1,49 @@ +package net.oschina.app.improve.account.bean; + +import java.io.Serializable; + +/** + * Created by fei + * on 2016/10/26. + * desc: + */ + +public class PhoneToken implements Serializable { + + private String phone; + private String token; + private String expireDate; + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + public String getExpireDate() { + return expireDate; + } + + public void setExpireDate(String expireDate) { + this.expireDate = expireDate; + } + + @Override + public String toString() { + return "PhoneToken{" + + "phone='" + phone + '\'' + + ", token='" + token + '\'' + + ", expireDate='" + expireDate + '\'' + + '}'; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/account/constants/UserConstants.java b/app/src/main/java/net/oschina/app/improve/account/constants/UserConstants.java new file mode 100644 index 0000000000000000000000000000000000000000..26ab27d58e100a1e3772d6a6390f1fb3f223fb6a --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/account/constants/UserConstants.java @@ -0,0 +1,14 @@ +package net.oschina.app.improve.account.constants; + +/** + * Created by fei + * on 2016/10/24. + * desc: + */ + +public interface UserConstants { + + String HOLD_ACCOUNT = "hold_account"; + String RETRIEVE_PWD_URL = "https://www.oschina.net/home/reset-pwd"; + +} diff --git a/app/src/main/java/net/oschina/app/improve/app/AppOperator.java b/app/src/main/java/net/oschina/app/improve/app/AppOperator.java new file mode 100644 index 0000000000000000000000000000000000000000..2eee06132f06575294e1057576c233821ef362f1 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/app/AppOperator.java @@ -0,0 +1,87 @@ +package net.oschina.app.improve.app; + +import com.bumptech.glide.load.model.GlideUrl; +import com.bumptech.glide.load.model.LazyHeaders; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonDeserializer; + +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.app.gson.DoubleJsonDeserializer; +import net.oschina.app.improve.app.gson.FloatJsonDeserializer; +import net.oschina.app.improve.app.gson.ImageJsonDeserializer; +import net.oschina.app.improve.app.gson.IntegerJsonDeserializer; +import net.oschina.app.improve.app.gson.StringJsonDeserializer; +import net.oschina.app.improve.bean.Tweet; + +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * Created by JuQiu + * on 16/6/24. + */ +public final class AppOperator { + private static ExecutorService EXECUTORS_INSTANCE; + private static Gson GSON_INSTANCE; + + public static Executor getExecutor() { + if (EXECUTORS_INSTANCE == null) { + synchronized (AppOperator.class) { + if (EXECUTORS_INSTANCE == null) { + EXECUTORS_INSTANCE = Executors.newFixedThreadPool(6); + } + } + } + return EXECUTORS_INSTANCE; + } + + public static void runOnThread(Runnable runnable) { + getExecutor().execute(runnable); + } + + public static GlideUrl getGlideUrlByUser(String url) { + if (AccountHelper.isLogin()) { + return new GlideUrl(url, + new LazyHeaders + .Builder() + .addHeader("Cookie", AccountHelper.getCookie()) + .build()); + } else { + return new GlideUrl(url); + } + } + + public static Gson createGson() { + GsonBuilder gsonBuilder = new GsonBuilder(); + //gsonBuilder.setExclusionStrategies(new SpecificClassExclusionStrategy(null, Model.class)); + gsonBuilder.setDateFormat("yyyy-MM-dd HH:mm:ss"); + + JsonDeserializer deserializer = new IntegerJsonDeserializer(); + gsonBuilder.registerTypeAdapter(int.class, deserializer); + gsonBuilder.registerTypeAdapter(Integer.class, deserializer); + + deserializer = new FloatJsonDeserializer(); + gsonBuilder.registerTypeAdapter(float.class, deserializer); + gsonBuilder.registerTypeAdapter(Float.class, deserializer); + + deserializer = new DoubleJsonDeserializer(); + gsonBuilder.registerTypeAdapter(double.class, deserializer); + gsonBuilder.registerTypeAdapter(Double.class, deserializer); + + deserializer = new StringJsonDeserializer(); + gsonBuilder.registerTypeAdapter(String.class, deserializer); + + gsonBuilder.registerTypeAdapter(Tweet.Image.class, new ImageJsonDeserializer()); + + return gsonBuilder.create(); + } + + public synchronized static Gson getGson() { + if (GSON_INSTANCE == null) + GSON_INSTANCE = createGson(); + return GSON_INSTANCE; + } + +} diff --git a/app/src/main/java/net/oschina/app/improve/app/gson/DoubleJsonDeserializer.java b/app/src/main/java/net/oschina/app/improve/app/gson/DoubleJsonDeserializer.java new file mode 100644 index 0000000000000000000000000000000000000000..3115b3059329fe4c96549f537153869ea04903cc --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/app/gson/DoubleJsonDeserializer.java @@ -0,0 +1,26 @@ +package net.oschina.app.improve.app.gson; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; + +import net.oschina.app.util.TLog; + +import java.lang.reflect.Type; + +/** + * Created by qiujuer + * on 2016/11/22. + */ +public class DoubleJsonDeserializer implements JsonDeserializer { + @Override + public Double deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + try { + return json.getAsDouble(); + } catch (Exception e) { + TLog.log("DoubleJsonDeserializer-deserialize-error:" + (json != null ? json.toString() : "")); + return 0D; + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/app/gson/FloatJsonDeserializer.java b/app/src/main/java/net/oschina/app/improve/app/gson/FloatJsonDeserializer.java new file mode 100644 index 0000000000000000000000000000000000000000..7d6c1f4ab2c37aeca61b940494e8ebcf6f97aca4 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/app/gson/FloatJsonDeserializer.java @@ -0,0 +1,26 @@ +package net.oschina.app.improve.app.gson; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; + +import net.oschina.app.util.TLog; + +import java.lang.reflect.Type; + +/** + * Created by qiujuer + * on 2016/11/22. + */ +public class FloatJsonDeserializer implements JsonDeserializer { + @Override + public Float deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + try { + return json.getAsFloat(); + } catch (Exception e) { + TLog.log("FloatJsonDeserializer-deserialize-error:" + (json != null ? json.toString() : "")); + return 0F; + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/app/gson/ImageJsonDeserializer.java b/app/src/main/java/net/oschina/app/improve/app/gson/ImageJsonDeserializer.java new file mode 100644 index 0000000000000000000000000000000000000000..3ff471c39bee21486f7a3caa29532a8c1da0ab61 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/app/gson/ImageJsonDeserializer.java @@ -0,0 +1,41 @@ +package net.oschina.app.improve.app.gson; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; + +import net.oschina.app.improve.bean.Tweet; +import net.oschina.app.util.TLog; + +import java.lang.reflect.Type; + +/** + * @author qiujuer Email:qiujuer@live.cn + * @version 1.0.0 + */ + +public class ImageJsonDeserializer implements JsonDeserializer { + @Override + public Tweet.Image deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + try { + if (json.isJsonObject()) { + Tweet.Image image = new Tweet.Image(); + // The whole object is available + final JsonObject jsonObject = json.getAsJsonObject(); + image.setThumb(context.deserialize(jsonObject.get("thumb"), String.class)); + image.setHref(context.deserialize(jsonObject.get("href"), String.class)); + image.setH(context.deserialize(jsonObject.get("h"), int.class)); + image.setW(context.deserialize(jsonObject.get("w"), int.class)); + if (Tweet.Image.check(image)) + return image; + else + return null; + } + } catch (Exception e) { + TLog.error("ImageJsonDeserializer-deserialize-error:" + (json != null ? json.toString() : "")); + } + return null; + } +} \ No newline at end of file diff --git a/app/src/main/java/net/oschina/app/improve/app/gson/IntegerJsonDeserializer.java b/app/src/main/java/net/oschina/app/improve/app/gson/IntegerJsonDeserializer.java new file mode 100644 index 0000000000000000000000000000000000000000..e5cf6d7d823086fa3274eef4c5a222f8fa56864f --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/app/gson/IntegerJsonDeserializer.java @@ -0,0 +1,26 @@ +package net.oschina.app.improve.app.gson; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; + +import net.oschina.app.util.TLog; + +import java.lang.reflect.Type; + +/** + * Created by qiujuer + * on 2016/11/22. + */ +public class IntegerJsonDeserializer implements JsonDeserializer { + @Override + public Integer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + try { + return json.getAsInt(); + } catch (Exception e) { + TLog.log("IntegerJsonDeserializer-deserialize-error:" + (json != null ? json.toString() : "")); + return 0; + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/app/gson/StringJsonDeserializer.java b/app/src/main/java/net/oschina/app/improve/app/gson/StringJsonDeserializer.java new file mode 100644 index 0000000000000000000000000000000000000000..1d55ea6a1281009a70c4b247990d2ced046ca222 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/app/gson/StringJsonDeserializer.java @@ -0,0 +1,26 @@ +package net.oschina.app.improve.app.gson; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; + +import net.oschina.app.util.TLog; + +import java.lang.reflect.Type; + +/** + * Created by qiujuer + * on 2016/11/22. + */ +public class StringJsonDeserializer implements JsonDeserializer { + @Override + public String deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + try { + return json.getAsString(); + } catch (Exception e) { + TLog.log("StringJsonDeserializer-deserialize-error:" + (json != null ? json.toString() : "")); + return null; + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/base/BaseListPresenter.java b/app/src/main/java/net/oschina/app/improve/base/BaseListPresenter.java new file mode 100644 index 0000000000000000000000000000000000000000..07e9fb9777afa92846cbaf28dfe4d274c07471d2 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/base/BaseListPresenter.java @@ -0,0 +1,12 @@ +package net.oschina.app.improve.base; + +/** + * Created by haibin + * on 2016/11/30. + */ + +public interface BaseListPresenter extends BasePresenter { + void onRefreshing(); + + void onLoadMore(); +} diff --git a/app/src/main/java/net/oschina/app/improve/base/BaseListView.java b/app/src/main/java/net/oschina/app/improve/base/BaseListView.java new file mode 100644 index 0000000000000000000000000000000000000000..dcc3964a227b1fa9e5521ac2271e43cb3685b211 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/base/BaseListView.java @@ -0,0 +1,25 @@ +package net.oschina.app.improve.base; + +import java.util.List; + +/** + * Created by haibin + * on 2016/11/30. + */ + +public interface BaseListView extends BaseView { + /** + * 刷新成功 + */ + void onRefreshSuccess(List data); + + /** + * 加载成功 + */ + void onLoadMoreSuccess(List data); + + /** + * 没有更多数据 + */ + void showNoreMore(); +} diff --git a/app/src/main/java/net/oschina/app/improve/base/BasePresenter.java b/app/src/main/java/net/oschina/app/improve/base/BasePresenter.java new file mode 100644 index 0000000000000000000000000000000000000000..c21c3e017271044e701cd4dd08a290f074e961c2 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/base/BasePresenter.java @@ -0,0 +1,10 @@ +package net.oschina.app.improve.base; + +/** + * Created by haibin + * on 2016/11/30. + */ + +public interface BasePresenter { + +} diff --git a/app/src/main/java/net/oschina/app/improve/base/BaseView.java b/app/src/main/java/net/oschina/app/improve/base/BaseView.java new file mode 100644 index 0000000000000000000000000000000000000000..b0a1a09d6b9240b7601051b91738a547d81243fd --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/base/BaseView.java @@ -0,0 +1,13 @@ +package net.oschina.app.improve.base; + +/** + * Created by haibin + * on 2016/11/30. + */ + +public interface BaseView { + + void setPresenter(Presenter presenter); + + void showNetworkError(int strId); +} diff --git a/app/src/main/java/net/oschina/app/improve/base/activities/BackActivity.java b/app/src/main/java/net/oschina/app/improve/base/activities/BackActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..319ac4ce3010fb16529bd5e7df3be98911c52367 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/base/activities/BackActivity.java @@ -0,0 +1,35 @@ +package net.oschina.app.improve.base.activities; + +import android.support.v7.app.ActionBar; +import android.support.v7.widget.Toolbar; + +import net.oschina.app.R; + +/** + * Created by haibin + * on 2016/12/1. + */ + +public abstract class BackActivity extends BaseActivity { + protected Toolbar mToolBar; + + @Override + protected void initWindow() { + super.initWindow(); + mToolBar = (Toolbar) findViewById(R.id.toolbar); + if (mToolBar != null) { + setSupportActionBar(mToolBar); + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setHomeButtonEnabled(false); + } + } + } + + @Override + public boolean onSupportNavigateUp() { + finish(); + return super.onSupportNavigateUp(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/base/activities/BaseActivity.java b/app/src/main/java/net/oschina/app/improve/base/activities/BaseActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..b5893f98607c50d02cd606090d67de74b19f3930 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/base/activities/BaseActivity.java @@ -0,0 +1,121 @@ +package net.oschina.app.improve.base.activities; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentTransaction; +import android.support.v7.app.AppCompatActivity; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.RequestManager; +import com.umeng.analytics.MobclickAgent; + +import butterknife.ButterKnife; + +/** + * Created by JuQiu + * on 16/6/20. + */ + +public abstract class BaseActivity extends AppCompatActivity { + protected RequestManager mImageLoader; + private boolean mIsDestroy; + private final String mPackageNameUmeng = this.getClass().getName(); + private Fragment mFragment; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + if (initBundle(getIntent().getExtras())) { + setContentView(getContentView()); + + initWindow(); + + ButterKnife.bind(this); + initWidget(); + initData(); + } else { + finish(); + } + + //umeng analytics + MobclickAgent.setDebugMode(false); + MobclickAgent.openActivityDurationTrack(false); + MobclickAgent.setScenarioType(this, MobclickAgent.EScenarioType.E_UM_NORMAL); + } + + protected void addFragment(int frameLayoutId, Fragment fragment) { + if (fragment != null) { + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + if (fragment.isAdded()) { + if (mFragment != null) { + transaction.hide(mFragment).show(fragment); + } else { + transaction.show(fragment); + } + } else { + if (mFragment != null) { + transaction.hide(mFragment).add(frameLayoutId, fragment); + } else { + transaction.add(frameLayoutId, fragment); + } + } + mFragment = fragment; + transaction.commit(); + } + } + + protected void replaceFragment(int frameLayoutId, Fragment fragment) { + if (fragment != null) { + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.replace(frameLayoutId, fragment); + transaction.commit(); + } + } + + @Override + protected void onResume() { + super.onResume(); + MobclickAgent.onPageStart(this.mPackageNameUmeng); + MobclickAgent.onResume(this); + } + + @Override + protected void onPause() { + super.onPause(); + MobclickAgent.onPageEnd(this.mPackageNameUmeng); + MobclickAgent.onPause(this); + } + + protected abstract int getContentView(); + + protected boolean initBundle(Bundle bundle) { + return true; + } + + protected void initWindow() { + } + + protected void initWidget() { + } + + protected void initData() { + } + + public synchronized RequestManager getImageLoader() { + if (mImageLoader == null) + mImageLoader = Glide.with(this); + return mImageLoader; + } + + @Override + protected void onDestroy() { + mIsDestroy = true; + super.onDestroy(); + } + + public boolean isDestroy() { + return mIsDestroy; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/base/activities/BaseBackActivity.java b/app/src/main/java/net/oschina/app/improve/base/activities/BaseBackActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..9aa708fa81b9fd7756769f58f39c52c5275b6552 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/base/activities/BaseBackActivity.java @@ -0,0 +1,32 @@ +package net.oschina.app.improve.base.activities; + +import android.support.v7.app.ActionBar; + +/** + * Created by JuQiu + * on 16/6/20. + */ + +public abstract class BaseBackActivity extends BaseActivity { + @Override + protected void initWindow() { + super.initWindow(); + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setHomeButtonEnabled(false); + } + } + + @Override + public boolean onSupportNavigateUp() { + finish(); + return super.onSupportNavigateUp(); + } + + @Override + public void onBackPressed() { + super.onBackPressed(); + finish(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/base/activities/BaseRecyclerViewActivity.java b/app/src/main/java/net/oschina/app/improve/base/activities/BaseRecyclerViewActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..b99a8c99a5b8782a321a4e82a2594dd76a6a8304 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/base/activities/BaseRecyclerViewActivity.java @@ -0,0 +1,200 @@ +package net.oschina.app.improve.base.activities; + +import android.content.Context; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; + +import com.bumptech.glide.RequestManager; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.R; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.base.adapter.BaseGeneralRecyclerAdapter; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.bean.base.PageBean; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.widget.RecyclerRefreshLayout; +import net.oschina.app.improve.widget.SimplexToast; + +import java.lang.reflect.Type; +import java.util.Date; + +import butterknife.Bind; +import cz.msebera.android.httpclient.Header; + +/** + * Created by huanghaibin_dev + * on 16-6-23. + */ +public abstract class BaseRecyclerViewActivity extends BaseBackActivity implements + BaseRecyclerAdapter.OnItemClickListener, + RecyclerRefreshLayout.SuperRefreshLayoutListener, + BaseGeneralRecyclerAdapter.Callback { + + @Bind(R.id.refreshLayout) + protected RecyclerRefreshLayout mRefreshLayout; + + @Bind(R.id.recyclerView) + protected RecyclerView mRecyclerView; + + protected BaseRecyclerAdapter mAdapter; + + protected TextHttpResponseHandler mHandler; + + protected PageBean mBean; + + protected boolean mIsRefresh; + + @Override + protected int getContentView() { + return R.layout.activity_base_recycler; + } + + @Override + protected void initWidget() { + super.initWidget(); + mAdapter = mAdapter == null ? getRecyclerAdapter() : mAdapter; + mRecyclerView.setLayoutManager(getLayoutManager()); + mRecyclerView.setAdapter(mAdapter); + mAdapter.setOnItemClickListener(this); + mRefreshLayout.setSuperRefreshLayoutListener(this); + mRefreshLayout.setColorSchemeResources( + R.color.swiperefresh_color1, R.color.swiperefresh_color2, + R.color.swiperefresh_color3, R.color.swiperefresh_color4); + } + + @Override + protected void initData() { + super.initData(); + mBean = new PageBean<>(); + mHandler = new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + onLoadingFailure(); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + ResultBean> resultBean = AppOperator.createGson().fromJson(responseString, getType()); + if (resultBean != null && resultBean.isSuccess() && resultBean.getResult().getItems() != null) { + onLoadingSuccess(); + setListData(resultBean); + } else { + if (resultBean.getCode() == ResultBean.RESULT_TOKEN_ERROR) { + SimplexToast.show(BaseRecyclerViewActivity.this, resultBean.getMessage()); + } + onLoadingFailure(); + } + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + } + + @Override + public void onStart() { + super.onStart(); + onLoadingStart(); + } + + @Override + public void onFinish() { + super.onFinish(); + onLoadingFinish(); + } + }; + + mRefreshLayout.post(new Runnable() { + @Override + public void run() { + mRefreshLayout.setRefreshing(true); + onRefreshing(); + } + }); + } + + @Override + public void onItemClick(int position, long itemId) { + onItemClick(mAdapter.getItem(position), position); + } + + @Override + public void onRefreshing() { + mIsRefresh = true; + requestData(); + } + + @Override + public void onLoadMore() { + requestData(); + } + + protected void onItemClick(T item, int position) { + + } + + protected void requestData() { + + } + + protected void setListData(ResultBean> resultBean) { + mBean.setNextPageToken(resultBean.getResult().getNextPageToken()); + mBean.setPrevPageToken(resultBean.getResult().getPrevPageToken()); + if (mIsRefresh) { + mBean.setItems(resultBean.getResult().getItems()); + mAdapter.clear(); + mAdapter.addAll(mBean.getItems()); + mBean.setPrevPageToken(resultBean.getResult().getPrevPageToken()); + mRefreshLayout.setCanLoadMore(true); + } else { + mAdapter.addAll(resultBean.getResult().getItems()); + } + mAdapter.setState(resultBean.getResult().getItems() == null || resultBean.getResult().getItems().size() < 20 ? BaseRecyclerAdapter.STATE_NO_MORE : BaseRecyclerAdapter.STATE_LOADING, true); + } + + protected void onLoadingStart() { + + } + + protected void onLoadingSuccess() { + + } + + protected void onLoadingFinish() { + mRefreshLayout.onComplete(); + mIsRefresh = false; + } + + protected void onLoadingFailure() { + if (mAdapter.getItems().size() == 0) { + mAdapter.setState(BaseRecyclerAdapter.STATE_LOAD_ERROR, true); + } else { + mAdapter.setState(BaseRecyclerAdapter.STATE_NO_MORE, true); + } + } + + + protected RecyclerView.LayoutManager getLayoutManager() { + return new LinearLayoutManager(this); + } + + protected abstract Type getType(); + + protected abstract BaseRecyclerAdapter getRecyclerAdapter(); + + @Override + public RequestManager getImgLoader() { + return getImageLoader(); + } + + @Override + public Context getContext() { + return this; + } + + @Override + public Date getSystemTime() { + return new Date(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/base/adapter/BaseGeneralRecyclerAdapter.java b/app/src/main/java/net/oschina/app/improve/base/adapter/BaseGeneralRecyclerAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..b8441b50e836b31933901c896d7afe649128944f --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/base/adapter/BaseGeneralRecyclerAdapter.java @@ -0,0 +1,77 @@ +package net.oschina.app.improve.base.adapter; + +import android.content.Context; +import android.text.Spannable; +import android.text.TextUtils; +import android.text.method.LinkMovementMethod; + +import com.bumptech.glide.RequestManager; + +import net.oschina.app.emoji.InputHelper; +import net.oschina.app.improve.utils.AssimilateUtils; +import net.oschina.app.widget.TweetTextView; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * Created by huanghaibin_dev + * on 2016/8/18. + */ + +public abstract class BaseGeneralRecyclerAdapter extends BaseRecyclerAdapter { + protected Callback mCallBack; + private List mPreItems; + + public BaseGeneralRecyclerAdapter(Callback callback, int mode) { + super(callback.getContext(), mode); + mCallBack = callback; + setState(STATE_LOADING, true); + } + + protected void parseAtUserContent(TweetTextView textView, String text) { + String content = ""; + if (TextUtils.isEmpty(text)) return; + content = text.replaceAll("[\n\\s]+", " "); + Spannable spannable = AssimilateUtils.assimilateOnlyAtUser(mCallBack.getContext(), content); + spannable = AssimilateUtils.assimilateOnlyTag(mCallBack.getContext(), spannable); + spannable = AssimilateUtils.assimilateOnlyLink(mCallBack.getContext(), spannable); + spannable = AssimilateUtils.assimilateOnlyTeamTask(mCallBack.getContext(), spannable); + spannable = InputHelper.displayEmoji(mCallBack.getContext().getResources(), spannable); + textView.setText(spannable); + textView.setMovementMethod(LinkMovementMethod.getInstance()); + textView.setFocusable(false); + textView.setDispatchToParent(true); + textView.setLongClickable(false); + } + + public void addItems(List items) { + if (items != null) { + List date = new ArrayList<>(); + if (mPreItems != null) { + for (T d : items) { + if (!mPreItems.contains(d)) { + date.add(d); + } + } + } else { + date = items; + } + mPreItems = items; + addAll(date); + } + } + + public void clearPreItems() { + mPreItems = null; + } + + public interface Callback { + RequestManager getImgLoader(); + + Context getContext(); + + Date getSystemTime(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/base/adapter/BaseListAdapter.java b/app/src/main/java/net/oschina/app/improve/base/adapter/BaseListAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..d99ab246569f610ee0216742381681386910a9b2 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/base/adapter/BaseListAdapter.java @@ -0,0 +1,157 @@ +package net.oschina.app.improve.base.adapter; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; + +import com.bumptech.glide.RequestManager; + +import net.oschina.app.adapter.ViewHolder; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * 通用的ViewHolder + *

    + * Created by 火蚁 on 15/4/8. + */ +@SuppressWarnings("unused") +public abstract class BaseListAdapter extends BaseAdapter implements ViewHolder.Callback { + protected LayoutInflater mInflater; + private List mDatas; + private List mPreData; + protected Callback mCallback; + + public BaseListAdapter(Callback callback) { + this.mCallback = callback; + this.mInflater = LayoutInflater.from(callback.getContext()); + this.mDatas = new ArrayList(); + } + + @Override + public int getCount() { + return mDatas.size(); + } + + @Override + public T getItem(int position) { + if (position >= 0 && position < mDatas.size()) + return mDatas.get(position); + return null; + } + + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + T time = getItem(position); + int layoutId = getLayoutId(position, time); + final ViewHolder vh = ViewHolder.getViewHolder(this, convertView, parent, layoutId, position); + convert(vh, time, position); + return vh.getConvertView(); + } + + public List getDatas() { + return this.mDatas; + } + + protected abstract void convert(ViewHolder vh, T item, int position); + + protected abstract int getLayoutId(int position, T item); + + public void updateItem(int location, T item) { + if (mDatas.isEmpty()) return; + mDatas.set(location, item); + notifyDataSetChanged(); + } + + public void addItem(T item) { + checkListNull(); + mDatas.add(item); + notifyDataSetChanged(); + } + + public void addItem(int location, T item) { + checkListNull(); + mDatas.add(location, item); + notifyDataSetChanged(); + } + + public void addItem(List items) { + checkListNull(); + if (items != null) { + List date = new ArrayList<>(); + if (mPreData != null) { + for (T d : items) { + if (!mPreData.contains(d)) { + date.add(d); + } + } + } else { + date = items; + } + mPreData = items; + mDatas.addAll(date); + } + notifyDataSetChanged(); + } + + public void addItem(int position, List items) { + checkListNull(); + mDatas.addAll(position, items); + notifyDataSetChanged(); + } + + public void removeItem(int location) { + if (mDatas == null || mDatas.isEmpty()) { + return; + } + mDatas.remove(location); + notifyDataSetChanged(); + } + + public void clear() { + if (mDatas == null || mDatas.isEmpty()) { + return; + } + mPreData = null; + mDatas.clear(); + notifyDataSetChanged(); + } + + public void checkListNull() { + if (mDatas == null) { + mDatas = new ArrayList(); + } + } + + public int getCurrentPage() { + return getCount() % 20; + } + + @Override + public RequestManager getImgLoader() { + return mCallback.getImgLoader(); + } + + @Override + public LayoutInflater getInflate() { + return mInflater; + } + + public interface Callback { + RequestManager getImgLoader(); + + Context getContext(); + + Date getSystemTime(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/base/adapter/BaseRecyclerAdapter.java b/app/src/main/java/net/oschina/app/improve/base/adapter/BaseRecyclerAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..77b637c60891ca674a8e2587190788688e7e4e9f --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/base/adapter/BaseRecyclerAdapter.java @@ -0,0 +1,419 @@ +package net.oschina.app.improve.base.adapter; + +import android.content.Context; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.StaggeredGridLayoutManager; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ProgressBar; +import android.widget.TextView; + +import net.oschina.app.R; + +import java.util.ArrayList; +import java.util.List; + +/** + * the base adapter for RecyclerView + * Created by huanghaibin on 16-5-3. + */ +@SuppressWarnings("unused") +public abstract class BaseRecyclerAdapter extends RecyclerView.Adapter { + protected List mItems; + protected Context mContext; + protected LayoutInflater mInflater; + + protected String mSystemTime; + + public static final int STATE_NO_MORE = 1; + public static final int STATE_LOAD_MORE = 2; + public static final int STATE_INVALID_NETWORK = 3; + public static final int STATE_HIDE = 5; + public static final int STATE_REFRESHING = 6; + public static final int STATE_LOAD_ERROR = 7; + public static final int STATE_LOADING = 8; + + public final int BEHAVIOR_MODE; + protected int mState; + + public static final int NEITHER = 0; + public static final int ONLY_HEADER = 1; + public static final int ONLY_FOOTER = 2; + public static final int BOTH_HEADER_FOOTER = 3; + + public static final int VIEW_TYPE_NORMAL = 0; + public static final int VIEW_TYPE_HEADER = -1; + public static final int VIEW_TYPE_FOOTER = -2; + + private OnItemClickListener onItemClickListener; + private OnItemLongClickListener onItemLongClickListener; + + private OnClickListener onClickListener; + private OnLongClickListener onLongClickListener; + + + protected View mHeaderView; + + private OnLoadingHeaderCallBack onLoadingHeaderCallBack; + + public BaseRecyclerAdapter(Context context, int mode) { + mItems = new ArrayList<>(); + this.mContext = context; + this.mInflater = LayoutInflater.from(context); + BEHAVIOR_MODE = mode; + mState = STATE_HIDE; + //mFooterView = mInflater.inflate(R.layout.footer_view, null); + initListener(); + } + + /** + * 初始化listener + */ + private void initListener() { + onClickListener = new OnClickListener() { + @Override + public void onClick(int position, long itemId) { + if (onItemClickListener != null) + onItemClickListener.onItemClick(position, itemId); + } + }; + + onLongClickListener = new OnLongClickListener() { + @Override + public boolean onLongClick(int position, long itemId) { + if (onItemLongClickListener != null) { + onItemLongClickListener.onLongClick(position, itemId); + return true; + } + return false; + } + }; + } + + public void setSystemTime(String systemTime) { + this.mSystemTime = systemTime; + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + switch (viewType) { + case VIEW_TYPE_HEADER: + if (onLoadingHeaderCallBack != null) + return onLoadingHeaderCallBack.onCreateHeaderHolder(parent); + else + throw new IllegalArgumentException("you have to impl the interface when using this viewType"); + case VIEW_TYPE_FOOTER: + return new FooterViewHolder(mInflater.inflate(R.layout.recycler_footer_view, parent, false)); + default: + final RecyclerView.ViewHolder holder = onCreateDefaultViewHolder(parent, viewType); + if (holder != null) { + holder.itemView.setTag(holder); + holder.itemView.setOnLongClickListener(onLongClickListener); + holder.itemView.setOnClickListener(onClickListener); + } + return holder; + } + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + switch (holder.getItemViewType()) { + case VIEW_TYPE_HEADER: + if (onLoadingHeaderCallBack != null) + onLoadingHeaderCallBack.onBindHeaderHolder(holder, position); + break; + case VIEW_TYPE_FOOTER: + FooterViewHolder fvh = (FooterViewHolder) holder; + fvh.itemView.setVisibility(View.VISIBLE); + switch (mState) { + case STATE_INVALID_NETWORK: + fvh.tv_footer.setText(mContext.getResources().getString(R.string.state_network_error)); + fvh.pb_footer.setVisibility(View.GONE); + break; + case STATE_LOAD_MORE: + case STATE_LOADING: + fvh.tv_footer.setText(mContext.getResources().getString(R.string.state_loading)); + fvh.pb_footer.setVisibility(View.VISIBLE); + break; + case STATE_NO_MORE: + fvh.tv_footer.setText(mContext.getResources().getString(R.string.state_not_more)); + fvh.pb_footer.setVisibility(View.GONE); + break; + case STATE_REFRESHING: + fvh.tv_footer.setText(mContext.getResources().getString(R.string.state_refreshing)); + fvh.pb_footer.setVisibility(View.GONE); + break; + case STATE_LOAD_ERROR: + fvh.tv_footer.setText(mContext.getResources().getString(R.string.state_load_error)); + fvh.pb_footer.setVisibility(View.GONE); + break; + case STATE_HIDE: + fvh.itemView.setVisibility(View.GONE); + break; + } + break; + default: + onBindDefaultViewHolder(holder, getItems().get(getIndex(position)), position); + break; + } + } + + + /** + * 当添加到RecyclerView时获取GridLayoutManager布局管理器,修正header和footer显示整行 + * + * @param recyclerView the mRecyclerView + */ + @Override + public void onAttachedToRecyclerView(RecyclerView recyclerView) { + super.onAttachedToRecyclerView(recyclerView); + RecyclerView.LayoutManager manager = recyclerView.getLayoutManager(); + if (manager instanceof GridLayoutManager) { + final GridLayoutManager gridManager = ((GridLayoutManager) manager); + gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { + @Override + public int getSpanSize(int position) { + return getItemViewType(position) == VIEW_TYPE_HEADER || getItemViewType(position) == VIEW_TYPE_FOOTER + ? gridManager.getSpanCount() : 1; + } + }); + } + } + + /** + * 当RecyclerView在windows活动时获取StaggeredGridLayoutManager布局管理器,修正header和footer显示整行 + * + * @param holder the RecyclerView.ViewHolder + */ + @Override + public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { + ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams(); + if (lp != null && lp instanceof StaggeredGridLayoutManager.LayoutParams) { + StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp; + if (BEHAVIOR_MODE == ONLY_HEADER) { + p.setFullSpan(holder.getLayoutPosition() == 0); + } else if (BEHAVIOR_MODE == ONLY_FOOTER) { + p.setFullSpan(holder.getLayoutPosition() == mItems.size() + 1); + } else if (BEHAVIOR_MODE == BOTH_HEADER_FOOTER) { + if (holder.getLayoutPosition() == 0 || holder.getLayoutPosition() == mItems.size() + 1) { + p.setFullSpan(true); + } + } + } + } + + @Override + public int getItemViewType(int position) { + if (position == 0 && (BEHAVIOR_MODE == ONLY_HEADER || BEHAVIOR_MODE == BOTH_HEADER_FOOTER)) + return VIEW_TYPE_HEADER; + if (position + 1 == getItemCount() && (BEHAVIOR_MODE == ONLY_FOOTER || BEHAVIOR_MODE == BOTH_HEADER_FOOTER)) + return VIEW_TYPE_FOOTER; + else return VIEW_TYPE_NORMAL; + } + + protected int getIndex(int position) { + return BEHAVIOR_MODE == ONLY_HEADER || BEHAVIOR_MODE == BOTH_HEADER_FOOTER ? position - 1 : position; + } + + @Override + public int getItemCount() { + if (BEHAVIOR_MODE == ONLY_FOOTER || BEHAVIOR_MODE == ONLY_HEADER) { + return mItems.size() + 1; + } else if (BEHAVIOR_MODE == BOTH_HEADER_FOOTER) { + return mItems.size() + 2; + } else return mItems.size(); + } + + public int getCount() { + return mItems.size(); + } + + protected abstract RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type); + + protected abstract void onBindDefaultViewHolder(RecyclerView.ViewHolder holder, T item, int position); + + public final View getHeaderView() { + return this.mHeaderView; + } + + public final void setHeaderView(View view) { + this.mHeaderView = view; + } + + public final List getItems() { + return mItems; + } + + + public void addAll(List items) { + if (items != null) { + this.mItems.addAll(items); + notifyItemRangeInserted(this.mItems.size(), items.size()); + } + } + + public final void addItem(T item) { + if (item != null) { + this.mItems.add(item); + notifyItemChanged(mItems.size()); + } + } + + + public void addItem(int position, T item) { + if (item != null) { + this.mItems.add(getIndex(position), item); + notifyItemInserted(position); + } + } + + public void replaceItem(int position, T item) { + if (item != null) { + this.mItems.set(getIndex(position), item); + notifyItemChanged(position); + } + } + + public void updateItem(int position) { + if (getItemCount() > position) { + notifyItemChanged(position); + } + } + + + public final void removeItem(T item) { + if (this.mItems.contains(item)) { + int position = mItems.indexOf(item); + this.mItems.remove(item); + notifyItemRemoved(position); + } + } + + public final void removeItem(int position) { + if (this.getItemCount() > position) { + this.mItems.remove(getIndex(position)); + notifyItemRemoved(position); + } + } + + public final T getItem(int position) { + int p = getIndex(position); + if (p < 0 || p >= mItems.size()) + return null; + return mItems.get(getIndex(position)); + } + + public final void resetItem(List items) { + if (items != null) { + clear(); + addAll(items); + } + } + + public final void clear() { + this.mItems.clear(); + setState(STATE_HIDE, false); + notifyDataSetChanged(); + } + + public void setState(int mState, boolean isUpdate) { + this.mState = mState; + if (isUpdate) + updateItem(getItemCount() - 1); + } + + public int getState() { + return mState; + } + + /** + * 添加项点击事件 + * + * @param onItemClickListener the RecyclerView item click listener + */ + public void setOnItemClickListener(OnItemClickListener onItemClickListener) { + this.onItemClickListener = onItemClickListener; + } + + /** + * 添加项点长击事件 + * + * @param onItemLongClickListener the RecyclerView item long click listener + */ + public void setOnItemLongClickListener(OnItemLongClickListener onItemLongClickListener) { + this.onItemLongClickListener = onItemLongClickListener; + } + + public final void setOnLoadingHeaderCallBack(OnLoadingHeaderCallBack listener) { + onLoadingHeaderCallBack = listener; + } + + + /** + * 可以共用同一个listener,相对高效 + */ + public static abstract class OnClickListener implements View.OnClickListener { + @Override + public void onClick(View v) { + RecyclerView.ViewHolder holder = (RecyclerView.ViewHolder) v.getTag(); + onClick(holder.getAdapterPosition(), holder.getItemId()); + } + + public abstract void onClick(int position, long itemId); + } + + + /** + * 可以共用同一个listener,相对高效 + */ + public static abstract class OnLongClickListener implements View.OnLongClickListener { + @Override + public boolean onLongClick(View v) { + RecyclerView.ViewHolder holder = (RecyclerView.ViewHolder) v.getTag(); + return onLongClick(holder.getAdapterPosition(), holder.getItemId()); + } + + public abstract boolean onLongClick(int position, long itemId); + } + + + /** + * + */ + public interface OnItemClickListener { + void onItemClick(int position, long itemId); + } + + + public interface OnItemLongClickListener { + void onLongClick(int position, long itemId); + } + + /** + * for load header view + */ + public interface OnLoadingHeaderCallBack { + RecyclerView.ViewHolder onCreateHeaderHolder(ViewGroup parent); + + void onBindHeaderHolder(RecyclerView.ViewHolder holder, int position); + } + + public static class FooterViewHolder extends RecyclerView.ViewHolder { + public ProgressBar pb_footer; + public TextView tv_footer; + + public FooterViewHolder(View view) { + super(view); + pb_footer = (ProgressBar) view.findViewById(R.id.pb_footer); + tv_footer = (TextView) view.findViewById(R.id.tv_footer); + } + } + + public class HeaderViewHolder extends RecyclerView.ViewHolder { + public HeaderViewHolder(View itemView) { + super(itemView); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/base/fragments/BaseFragment.java b/app/src/main/java/net/oschina/app/improve/base/fragments/BaseFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..d6ec01f6576aedf4d142be88d071415b67b97a78 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/base/fragments/BaseFragment.java @@ -0,0 +1,218 @@ +package net.oschina.app.improve.base.fragments; + +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.RequestManager; + +import net.oschina.app.util.ImageLoader; + +import java.io.Serializable; + +import butterknife.ButterKnife; + +/** + * Fragment基础类 + */ + +@SuppressWarnings("WeakerAccess") +public abstract class BaseFragment extends Fragment { + protected Context mContext; + protected View mRoot; + protected Bundle mBundle; + private RequestManager mImgLoader; + protected LayoutInflater mInflater; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + mContext = context; + } + + @Override + public void onDetach() { + super.onDetach(); + mContext = null; + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mBundle = getArguments(); + initBundle(mBundle); + } + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + if (mRoot != null) { + ViewGroup parent = (ViewGroup) mRoot.getParent(); + if (parent != null) + parent.removeView(mRoot); + } else { + mRoot = inflater.inflate(getLayoutId(), container, false); + mInflater = inflater; + // Do something + onBindViewBefore(mRoot); + // Bind view + ButterKnife.bind(this, mRoot); + // Get savedInstanceState + if (savedInstanceState != null) + onRestartInstance(savedInstanceState); + // Init + initWidget(mRoot); + initData(); + } + return mRoot; + } + + protected void onBindViewBefore(View root) { + // ... + } + + @Override + public void onDestroy() { + super.onDestroy(); + ButterKnife.unbind(this); + RequestManager manager = mImgLoader; + if (manager != null) + manager.onDestroy(); + mBundle = null; + } + + protected abstract int getLayoutId(); + + protected void initBundle(Bundle bundle) { + + } + + protected void initWidget(View root) { + + } + + protected void initData() { + + } + + protected T findView(int viewId) { + return (T) mRoot.findViewById(viewId); + } + + protected T getBundleSerializable(String key) { + if (mBundle == null) { + return null; + } + return (T) mBundle.getSerializable(key); + } + + /** + * 获取一个图片加载管理器 + * + * @return RequestManager + */ + public synchronized RequestManager getImgLoader() { + if (mImgLoader == null) + mImgLoader = Glide.with(this); + return mImgLoader; + } + + /*** + * 从网络中加载数据 + * + * @param viewId view的id + * @param imageUrl 图片地址 + */ + protected void setImageFromNet(int viewId, String imageUrl) { + setImageFromNet(viewId, imageUrl, 0); + } + + /*** + * 从网络中加载数据 + * + * @param viewId view的id + * @param imageUrl 图片地址 + * @param placeholder 图片地址为空时的资源 + */ + protected void setImageFromNet(int viewId, String imageUrl, int placeholder) { + ImageView imageView = findView(viewId); + setImageFromNet(imageView, imageUrl, placeholder); + } + + /*** + * 从网络中加载数据 + * + * @param imageView imageView + * @param imageUrl 图片地址 + */ + protected void setImageFromNet(ImageView imageView, String imageUrl) { + setImageFromNet(imageView, imageUrl, 0); + } + + /*** + * 从网络中加载数据 + * + * @param imageView imageView + * @param imageUrl 图片地址 + * @param placeholder 图片地址为空时的资源 + */ + protected void setImageFromNet(ImageView imageView, String imageUrl, int placeholder) { + ImageLoader.loadImage(getImgLoader(), imageView, imageUrl, placeholder); + } + + + protected void setText(int viewId, String text) { + TextView textView = findView(viewId); + if (TextUtils.isEmpty(text)) { + return; + } + textView.setText(text); + } + + protected void setText(int viewId, String text, String emptyTip) { + TextView textView = findView(viewId); + if (TextUtils.isEmpty(text)) { + textView.setText(emptyTip); + return; + } + textView.setText(text); + } + + protected void setTextEmptyGone(int viewId, String text) { + TextView textView = findView(viewId); + if (TextUtils.isEmpty(text)) { + textView.setVisibility(View.GONE); + return; + } + textView.setText(text); + } + + protected T setGone(int id) { + T view = findView(id); + view.setVisibility(View.GONE); + return view; + } + + protected T setVisibility(int id) { + T view = findView(id); + view.setVisibility(View.VISIBLE); + return view; + } + + protected void setInVisibility(int id) { + findView(id).setVisibility(View.INVISIBLE); + } + + protected void onRestartInstance(Bundle bundle) { + + } +} diff --git a/app/src/main/java/net/oschina/app/improve/base/fragments/BaseGeneralListFragment.java b/app/src/main/java/net/oschina/app/improve/base/fragments/BaseGeneralListFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..0dbb1799f6450da1bffc4bdc10685de113646514 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/base/fragments/BaseGeneralListFragment.java @@ -0,0 +1,19 @@ +package net.oschina.app.improve.base.fragments; + +import net.oschina.app.interf.OnTabReselectListener; + +/** + * Created by JuQiu + * on 16/6/6. + */ + +public abstract class BaseGeneralListFragment extends BaseListFragment implements OnTabReselectListener { + @Override + public void onTabReselect() { + if (mListView != null) { + mListView.setSelection(0); + mRefreshLayout.setRefreshing(true); + onRefreshing(); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/base/fragments/BaseGeneralRecyclerFragment.java b/app/src/main/java/net/oschina/app/improve/base/fragments/BaseGeneralRecyclerFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..2da7430e16028065e6eeeb63f1a8955f026fc250 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/base/fragments/BaseGeneralRecyclerFragment.java @@ -0,0 +1,18 @@ +package net.oschina.app.improve.base.fragments; + +import net.oschina.app.interf.OnTabReselectListener; + +/** + * Created by huanghaibin_dev + * on 2016/8/30. + */ +public abstract class BaseGeneralRecyclerFragment extends BaseRecyclerViewFragment implements OnTabReselectListener { + @Override + public void onTabReselect() { + if (mRecyclerView != null && !isRefreshing) { + mRecyclerView.scrollToPosition(0); + mRefreshLayout.setRefreshing(true); + onRefreshing(); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/base/fragments/BaseListFragment.java b/app/src/main/java/net/oschina/app/improve/base/fragments/BaseListFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..d9ba78949ea9d79eaba4c583ba8822aefb1ad454 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/base/fragments/BaseListFragment.java @@ -0,0 +1,262 @@ +package net.oschina.app.improve.base.fragments; + +import android.view.LayoutInflater; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ListView; +import android.widget.ProgressBar; +import android.widget.TextView; + +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.R; +import net.oschina.app.cache.CacheManager; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.base.adapter.BaseListAdapter; +import net.oschina.app.improve.bean.base.PageBean; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.ui.empty.EmptyLayout; +import net.oschina.app.widget.SuperRefreshLayout; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Date; + +import cz.msebera.android.httpclient.Header; + +/** + * T as the base bean + * Created by huanghaibin + * on 16-5-23. + */ +public abstract class BaseListFragment extends BaseFragment implements + SuperRefreshLayout.SuperRefreshLayoutListener, + AdapterView.OnItemClickListener, BaseListAdapter.Callback, + View.OnClickListener { + + public static final int TYPE_NORMAL = 0; + public static final int TYPE_LOADING = 1; + public static final int TYPE_NO_MORE = 2; + public static final int TYPE_ERROR = 3; + public static final int TYPE_NET_ERROR = 4; + protected String CACHE_NAME = getClass().getName(); + protected ListView mListView; + protected SuperRefreshLayout mRefreshLayout; + protected EmptyLayout mErrorLayout; + protected BaseListAdapter mAdapter; + protected boolean mIsRefresh; + protected TextHttpResponseHandler mHandler; + protected PageBean mBean; + private String mTime; + private View mFooterView; + private ProgressBar mFooterProgressBar; + private TextView mFooterText; + + @Override + protected int getLayoutId() { + return R.layout.fragment_base_list; + } + + @Override + protected void initWidget(View root) { + super.initWidget(root); + mListView = (ListView) root.findViewById(R.id.listView); + mRefreshLayout = (SuperRefreshLayout) root.findViewById(R.id.superRefreshLayout); + mRefreshLayout.setColorSchemeResources( + R.color.swiperefresh_color1, R.color.swiperefresh_color2, + R.color.swiperefresh_color3, R.color.swiperefresh_color4); + mErrorLayout = (EmptyLayout) root.findViewById(R.id.error_layout); + mRefreshLayout.setSuperRefreshLayoutListener(this); + mFooterView = LayoutInflater.from(getContext()).inflate(R.layout.layout_list_view_footer, null); + mFooterText = (TextView) mFooterView.findViewById(R.id.tv_footer); + mFooterProgressBar = (ProgressBar) mFooterView.findViewById(R.id.pb_footer); + mListView.setOnItemClickListener(this); + + mErrorLayout.setOnLayoutClickListener(this); + if (isNeedFooter()) + mListView.addFooterView(mFooterView); + } + + @Override + protected void initData() { + super.initData(); + //when open this fragment,read the obj + + mAdapter = getListAdapter(); + mListView.setAdapter(mAdapter); + + mHandler = new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + onRequestError(statusCode); + onRequestFinish(); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + ResultBean> resultBean = AppOperator.createGson().fromJson(responseString, getType()); + if (resultBean != null && resultBean.isSuccess() && resultBean.getResult().getItems() != null) { + onRequestSuccess(resultBean.getCode()); + setListData(resultBean); + } else { + setFooterType(TYPE_NO_MORE); + //mRefreshLayout.setNoMoreData(); + } + onRequestFinish(); + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + } + }; + + AppOperator.runOnThread(new Runnable() { + @Override + public void run() { + mBean = (PageBean) CacheManager.readObject(getActivity(), CACHE_NAME); + //if is the first loading + if (mBean == null) { + mBean = new PageBean<>(); + mBean.setItems(new ArrayList()); + onRefreshing(); + } else { + mRoot.post(new Runnable() { + @Override + public void run() { + mAdapter.addItem(mBean.getItems()); + mErrorLayout.setErrorType(EmptyLayout.HIDE_LAYOUT); + mRefreshLayout.setVisibility(View.VISIBLE); + onRefreshing(); + } + }); + } + } + }); + } + + @Override + public void onClick(View v) { + mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING); + onRefreshing(); + } + + @Override + public void onRefreshing() { + mIsRefresh = true; + requestData(); + } + + @Override + public void onLoadMore() { + requestData(); + } + + /** + * request network data + */ + protected void requestData() { + onRequestStart(); + setFooterType(TYPE_LOADING); + } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + + } + + protected void onRequestStart() { + + } + + protected void onRequestSuccess(int code) { + + } + + protected void onRequestError(int code) { + setFooterType(TYPE_NET_ERROR); + if (mAdapter.getDatas().size() == 0) + mErrorLayout.setErrorType(EmptyLayout.NETWORK_ERROR); + } + + protected void onRequestFinish() { + onComplete(); + } + + protected void onComplete() { + mRefreshLayout.onLoadComplete(); + mIsRefresh = false; + } + + protected void setListData(ResultBean> resultBean) { + //is refresh + mBean.setNextPageToken(resultBean.getResult().getNextPageToken()); + if (mIsRefresh) { + //cache the time + mTime = resultBean.getTime(); + mBean.setItems(resultBean.getResult().getItems()); + mAdapter.clear(); + mAdapter.addItem(mBean.getItems()); + mBean.setPrevPageToken(resultBean.getResult().getPrevPageToken()); + mRefreshLayout.setCanLoadMore(); + AppOperator.runOnThread(new Runnable() { + @Override + public void run() { + CacheManager.saveObject(getActivity(), mBean, CACHE_NAME); + } + }); + } else { + mAdapter.addItem(resultBean.getResult().getItems()); + } + if (resultBean.getResult().getItems().size() < 20) { + setFooterType(TYPE_NO_MORE); + //mRefreshLayout.setNoMoreData(); + } + if (mAdapter.getDatas().size() > 0) { + mErrorLayout.setErrorType(EmptyLayout.HIDE_LAYOUT); + mRefreshLayout.setVisibility(View.VISIBLE); + } else { + mErrorLayout.setErrorType(EmptyLayout.NODATA); + } + } + + @Override + public Date getSystemTime() { + return new Date(); + } + + protected abstract BaseListAdapter getListAdapter(); + + protected abstract Type getType(); + + protected boolean isNeedFooter() { + return true; + } + + + protected void setFooterType(int type) { + try { + switch (type) { + case TYPE_NORMAL: + case TYPE_LOADING: + mFooterText.setText(getResources().getString(R.string.footer_type_loading)); + mFooterProgressBar.setVisibility(View.VISIBLE); + break; + case TYPE_NET_ERROR: + mFooterText.setText(getResources().getString(R.string.footer_type_net_error)); + mFooterProgressBar.setVisibility(View.GONE); + break; + case TYPE_ERROR: + mFooterText.setText(getResources().getString(R.string.footer_type_error)); + mFooterProgressBar.setVisibility(View.GONE); + break; + case TYPE_NO_MORE: + mFooterText.setText(getResources().getString(R.string.footer_type_not_more)); + mFooterProgressBar.setVisibility(View.GONE); + break; + } + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/base/fragments/BaseRecyclerViewFragment.java b/app/src/main/java/net/oschina/app/improve/base/fragments/BaseRecyclerViewFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..dac76415e5e5a2a3eca4c90c8001718b7a4bd819 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/base/fragments/BaseRecyclerViewFragment.java @@ -0,0 +1,294 @@ +package net.oschina.app.improve.base.fragments; + +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.View; + +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.AppConfig; +import net.oschina.app.R; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.base.adapter.BaseGeneralRecyclerAdapter; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.bean.base.PageBean; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.utils.CacheManager; +import net.oschina.app.improve.widget.RecyclerRefreshLayout; +import net.oschina.app.improve.widget.SimplexToast; +import net.oschina.app.ui.empty.EmptyLayout; +import net.oschina.app.util.TDevice; +import net.oschina.app.util.TLog; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import cz.msebera.android.httpclient.Header; + + +/** + * 基本列表类,重写getLayoutId()自定义界面 + * Created by huanghaibin_dev + * on 2016/4/12. + */ +public abstract class BaseRecyclerViewFragment extends BaseFragment implements + RecyclerRefreshLayout.SuperRefreshLayoutListener, + BaseRecyclerAdapter.OnItemClickListener, + View.OnClickListener, + BaseGeneralRecyclerAdapter.Callback { + private final String TAG = this.getClass().getSimpleName(); + protected BaseRecyclerAdapter mAdapter; + protected RecyclerView mRecyclerView; + protected RecyclerRefreshLayout mRefreshLayout; + protected boolean isRefreshing; + protected TextHttpResponseHandler mHandler; + protected PageBean mBean; + protected String CACHE_NAME = getClass().getName(); + protected EmptyLayout mErrorLayout; + + @Override + public int getLayoutId() { + return R.layout.fragment_base_recycler_view; + } + + @Override + protected void initWidget(View root) { + mRecyclerView = (RecyclerView) root.findViewById(R.id.recyclerView); + mRefreshLayout = (RecyclerRefreshLayout) root.findViewById(R.id.refreshLayout); + mErrorLayout = (EmptyLayout) root.findViewById(R.id.error_layout); + } + + @SuppressWarnings("unchecked") + @Override + public void initData() { + mBean = new PageBean<>(); + mAdapter = getRecyclerAdapter(); + mAdapter.setState(BaseRecyclerAdapter.STATE_HIDE, false); + mRecyclerView.setAdapter(mAdapter); + mAdapter.setOnItemClickListener(this); + mErrorLayout.setOnLayoutClickListener(this); + mRefreshLayout.setSuperRefreshLayoutListener(this); + mAdapter.setState(BaseRecyclerAdapter.STATE_HIDE, false); + mRecyclerView.setLayoutManager(getLayoutManager()); + mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + super.onScrollStateChanged(recyclerView, newState); + if (RecyclerView.SCROLL_STATE_DRAGGING == newState && getActivity() != null + && getActivity().getCurrentFocus() != null) { + TDevice.hideSoftKeyboard(getActivity().getCurrentFocus()); + } + } + }); + mRefreshLayout.setColorSchemeResources( + R.color.swiperefresh_color1, R.color.swiperefresh_color2, + R.color.swiperefresh_color3, R.color.swiperefresh_color4); + + + mHandler = new TextHttpResponseHandler() { + @Override + public void onStart() { + super.onStart(); + log("HttpResponseHandler:onStart"); + } + + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + onRequestError(); + log("HttpResponseHandler:onFailure responseString:" + responseString); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + log("HttpResponseHandler:onSuccess responseString:" + responseString); + try { + ResultBean> resultBean = AppOperator.createGson().fromJson(responseString, getType()); + if (resultBean != null && resultBean.isSuccess() && resultBean.getResult().getItems() != null) { + setListData(resultBean); + onRequestSuccess(resultBean.getCode()); + } else { + if (resultBean.getCode() == ResultBean.RESULT_TOKEN_ERROR) { + SimplexToast.show(getActivity(), resultBean.getMessage()); + } + mAdapter.setState(BaseRecyclerAdapter.STATE_NO_MORE, true); + } + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + } + + @Override + public void onFinish() { + super.onFinish(); + onRequestFinish(); + log("HttpResponseHandler:onFinish"); + } + }; + + boolean isNeedEmptyView = isNeedEmptyView(); + if (isNeedEmptyView) { + mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING); + mRefreshLayout.setVisibility(View.GONE); + mBean = new PageBean<>(); + + List items = isNeedCache() + ? (List) CacheManager.readListJson(getActivity(), CACHE_NAME, getCacheClass()) + : null; + + mBean.setItems(items); + //if is the first loading + if (items == null) { + mBean.setItems(new ArrayList()); + onRefreshing(); + } else { + mAdapter.addAll(mBean.getItems()); + mErrorLayout.setErrorType(EmptyLayout.HIDE_LAYOUT); + mRefreshLayout.setVisibility(View.VISIBLE); + mRoot.post(new Runnable() { + @Override + public void run() { + mRefreshLayout.setRefreshing(true); + onRefreshing(); + } + }); + } + } else { + mErrorLayout.setErrorType(EmptyLayout.HIDE_LAYOUT); + mRefreshLayout.setVisibility(View.VISIBLE); + mRefreshLayout.post(new Runnable() { + @Override + public void run() { + mRefreshLayout.setRefreshing(true); + onRefreshing(); + } + }); + } + } + + @Override + public void onClick(View v) { + mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING); + onRefreshing(); + } + + + @Override + public void onItemClick(int position, long itemId) { + + } + + @Override + public void onRefreshing() { + isRefreshing = true; + requestData(); + } + + @Override + public void onLoadMore() { + mAdapter.setState(BaseRecyclerAdapter.STATE_LOADING, true); + requestData(); + } + + protected void requestData() { + } + + protected void onRequestSuccess(int code) { + + } + + protected void onRequestFinish() { + onComplete(); + } + + protected void onRequestError() { + if (mAdapter.getItems().size() == 0) { + if (isNeedEmptyView()) mErrorLayout.setErrorType(EmptyLayout.NETWORK_ERROR); + mAdapter.setState(BaseRecyclerAdapter.STATE_LOAD_ERROR, true); + } + } + + protected void onComplete() { + mRefreshLayout.onComplete(); + isRefreshing = false; + } + + protected void setListData(ResultBean> resultBean) { + mBean.setNextPageToken(resultBean.getResult().getNextPageToken()); + if (isRefreshing) { + AppConfig.getAppConfig(getActivity()).set("system_time", resultBean.getTime()); + mBean.setItems(resultBean.getResult().getItems()); + mAdapter.clear(); + mAdapter.addAll(mBean.getItems()); + mBean.setPrevPageToken(resultBean.getResult().getPrevPageToken()); + mRefreshLayout.setCanLoadMore(true); + if (isNeedCache()) { + CacheManager.saveToJson(getActivity(), CACHE_NAME, mBean.getItems()); + } + } else { + mAdapter.addAll(resultBean.getResult().getItems()); + } + + mAdapter.setState(resultBean.getResult().getItems() == null + || resultBean.getResult().getItems().size() < 20 + ? BaseRecyclerAdapter.STATE_NO_MORE + : BaseRecyclerAdapter.STATE_LOADING, true); + + if (mAdapter.getItems().size() > 0) { + mErrorLayout.setErrorType(EmptyLayout.HIDE_LAYOUT); + mRefreshLayout.setVisibility(View.VISIBLE); + mRecyclerView.setVisibility(View.VISIBLE); + } else { + mErrorLayout.setErrorType( + isNeedEmptyView() + ? EmptyLayout.NODATA + : EmptyLayout.HIDE_LAYOUT); + } + } + + protected RecyclerView.LayoutManager getLayoutManager() { + return new LinearLayoutManager(getActivity()); + } + + protected abstract BaseRecyclerAdapter getRecyclerAdapter(); + + protected abstract Type getType(); + + /** + * 获取缓存bean的class + */ + protected Class getCacheClass() { + return null; + } + + @Override + public Date getSystemTime() { + return new Date(); + } + + /** + * 需要缓存 + * + * @return isNeedCache + */ + protected boolean isNeedCache() { + return true; + } + + /** + * 需要空的View + * + * @return isNeedEmptyView + */ + protected boolean isNeedEmptyView() { + return true; + } + + @SuppressWarnings("ConstantConditions") + private void log(String msg) { + if (false) + TLog.i(TAG, msg); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/base/fragments/BaseTitleFragment.java b/app/src/main/java/net/oschina/app/improve/base/fragments/BaseTitleFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..62fd1afc4ea23dc0b2cb8f2a88b1b68ad10fb391 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/base/fragments/BaseTitleFragment.java @@ -0,0 +1,61 @@ +package net.oschina.app.improve.base.fragments; + +import android.support.annotation.DrawableRes; +import android.support.annotation.LayoutRes; +import android.support.annotation.StringRes; +import android.view.View; +import android.view.ViewStub; + +import net.oschina.app.R; +import net.oschina.app.improve.widget.TitleBar; + +/** + * Created by JuQiu + * on 16/9/5. + */ +public abstract class BaseTitleFragment extends BaseFragment { + + TitleBar mTitleBar; + + @Override + protected int getLayoutId() { + return R.layout.fragment_base_title; + } + + @Override + protected void onBindViewBefore(View root) { + super.onBindViewBefore(root); + // on before onBindViewBefore call + ViewStub stub = (ViewStub) root.findViewById(R.id.lay_content); + stub.setLayoutResource(getContentLayoutId()); + stub.inflate(); + } + + @Override + protected void initWidget(View root) { + super.initWidget(root); + // not null + mTitleBar = (TitleBar) root.findViewById(R.id.nav_title_bar); + mTitleBar.setTitle(getTitleRes()); + mTitleBar.setIcon(getIconRes()); + mTitleBar.setIconOnClickListener(getIconClickListener()); + } + + protected abstract + @LayoutRes + int getContentLayoutId(); + + protected abstract + @StringRes + int getTitleRes(); + + protected + @DrawableRes + int getIconRes() { + return 0; + } + + protected View.OnClickListener getIconClickListener() { + return null; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/base/fragments/BaseViewPagerFragment.java b/app/src/main/java/net/oschina/app/improve/base/fragments/BaseViewPagerFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..ec2780ef74334d74af74a0540282cfe098034297 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/base/fragments/BaseViewPagerFragment.java @@ -0,0 +1,102 @@ +package net.oschina.app.improve.base.fragments; + +import android.os.Bundle; +import android.support.design.widget.TabLayout; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentPagerAdapter; +import android.support.v4.view.PagerAdapter; +import android.support.v4.view.ViewPager; +import android.view.View; +import android.view.ViewGroup; + +import net.oschina.app.R; + +import butterknife.Bind; + +/** + * Created by fei + * on 2016/9/5. + *

    + * Changed qiujuer + * on 2016/9/5. + */ +public abstract class BaseViewPagerFragment extends BaseTitleFragment { + + @Bind(R.id.tab_nav) + protected TabLayout mTabNav; + + @Bind(R.id.base_viewPager) + protected ViewPager mBaseViewPager; + + @Override + protected int getContentLayoutId() { + return R.layout.fragment_base_viewpager; + } + + @Override + protected void initWidget(View root) { + super.initWidget(root); + BaseViewPagerAdapter adapter = new BaseViewPagerAdapter(getChildFragmentManager(), getPagers()); + mBaseViewPager.setAdapter(adapter); + mTabNav.setupWithViewPager(mBaseViewPager); + mBaseViewPager.setCurrentItem(0, true); + } + + protected abstract PagerInfo[] getPagers(); + + public static class PagerInfo { + private String title; + private Class clx; + private Bundle args; + + public PagerInfo(String title, Class clx, Bundle args) { + this.title = title; + this.clx = clx; + this.args = args; + } + } + + public class BaseViewPagerAdapter extends FragmentPagerAdapter { + private PagerInfo[] mInfoList; + private Fragment mCurFragment; + + public BaseViewPagerAdapter(FragmentManager fm, PagerInfo[] infoList) { + super(fm); + mInfoList = infoList; + } + + @Override + public void setPrimaryItem(ViewGroup container, int position, Object object) { + super.setPrimaryItem(container, position, object); + if (object instanceof Fragment) { + mCurFragment = (Fragment) object; + } + } + + public Fragment getCurFragment() { + return mCurFragment; + } + + @Override + public Fragment getItem(int position) { + PagerInfo info = mInfoList[position]; + return Fragment.instantiate(getContext(), info.clx.getName(), info.args); + } + + @Override + public int getCount() { + return mInfoList.length; + } + + @Override + public CharSequence getPageTitle(int position) { + return mInfoList[position].title; + } + + @Override + public int getItemPosition(Object object) { + return PagerAdapter.POSITION_NONE; + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/Active.java b/app/src/main/java/net/oschina/app/improve/bean/Active.java new file mode 100644 index 0000000000000000000000000000000000000000..0c7d1fbaa23c0c28658e87415709cc0360d1c32e --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/Active.java @@ -0,0 +1,59 @@ +package net.oschina.app.improve.bean; + +import net.oschina.app.improve.bean.simple.Author; +import net.oschina.app.improve.bean.simple.Origin; + +import java.io.Serializable; + +/** + * Created by thanatos on 16/8/16. + */ +public class Active implements Serializable { + + private long id; + private String content; + private String pubDate; + private Author author; + private Origin origin; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getPubDate() { + return pubDate; + } + + public void setPubDate(String pubDate) { + this.pubDate = pubDate; + } + + public Author getAuthor() { + return author; + } + + public void setAuthor(Author author) { + this.author = author; + } + + public Origin getOrigin() { + return origin; + } + + public void setOrigin(Origin origin) { + this.origin = origin; + } + +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/Blog.java b/app/src/main/java/net/oschina/app/improve/bean/Blog.java new file mode 100644 index 0000000000000000000000000000000000000000..b5533054122ec7776a199ed9862bb6b9a753630b --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/Blog.java @@ -0,0 +1,100 @@ +package net.oschina.app.improve.bean; + +/** + * Created by fei on 2016/5/24. + * desc: blog bean + */ +public class Blog extends PrimaryBean { + private String title; + private String body; + private String author; + private String pubDate; + private int commentCount; + private int viewCount; + private String href; + private boolean recommend; //是否推荐 + private boolean original; //是否原创 + private int type; //博客类型 1:常规, 2: 热门 3:最近 + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getPubDate() { + return pubDate; + } + + public void setPubDate(String pubDate) { + this.pubDate = pubDate; + } + + public int getCommentCount() { + return commentCount; + } + + public void setCommentCount(int commentCount) { + this.commentCount = commentCount; + } + + public int getViewCount() { + return viewCount; + } + + public void setViewCount(int viewCount) { + this.viewCount = viewCount; + } + + public String getHref() { + return href; + } + + public void setHref(String href) { + this.href = href; + } + + public boolean isRecommend() { + return recommend; + } + + public void setRecommend(boolean recommend) { + this.recommend = recommend; + } + + public boolean isOriginal() { + return original; + } + + public void setOriginal(boolean original) { + this.original = original; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + +} + diff --git a/app/src/main/java/net/oschina/app/improve/bean/BlogDetail.java b/app/src/main/java/net/oschina/app/improve/bean/BlogDetail.java new file mode 100644 index 0000000000000000000000000000000000000000..cafda549c9caf902e706c84f410ad793fd2baff4 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/BlogDetail.java @@ -0,0 +1,87 @@ +package net.oschina.app.improve.bean; + +import com.google.gson.annotations.SerializedName; + +import net.oschina.app.improve.bean.simple.About; + +import java.util.List; + +/** + * Created by qiujuer + */ +public class BlogDetail extends Blog { + private boolean favorite; + private long authorId; + private String authorPortrait; + private int authorRelation; + private String category; + @SerializedName("abstract") + private String abstractStr; + private List abouts; + private String notifyUrl; + + public String getNotifyUrl() { + return notifyUrl; + } + + public void setNotifyUrl(String notifyUrl) { + this.notifyUrl = notifyUrl; + } + + public long getAuthorId() { + return authorId; + } + + public void setAuthorId(long authorId) { + this.authorId = authorId; + } + + public String getAuthorPortrait() { + return authorPortrait; + } + + public void setAuthorPortrait(String authorPortrait) { + this.authorPortrait = authorPortrait; + } + + public int getAuthorRelation() { + return authorRelation; + } + + public void setAuthorRelation(int authorRelation) { + this.authorRelation = authorRelation; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public List getAbouts() { + return abouts; + } + + public void setAbouts(List abouts) { + this.abouts = abouts; + } + + public String getAbstract() { + return abstractStr; + } + + public void setAbstract(String abstractStr) { + this.abstractStr = abstractStr; + } + + public boolean isFavorite() { + return favorite; + } + + public void setFavorite(boolean favorite) { + this.favorite = favorite; + } +} + diff --git a/app/src/main/java/net/oschina/app/improve/bean/Collection.java b/app/src/main/java/net/oschina/app/improve/bean/Collection.java new file mode 100644 index 0000000000000000000000000000000000000000..c8faf591030c3c6b3fc094f595fe392a6fd0acb7 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/Collection.java @@ -0,0 +1,101 @@ +package net.oschina.app.improve.bean; + +import java.io.Serializable; + +/** + * Created by haibin + * on 2016/10/18. + */ + +public class Collection implements Serializable { + private long id; + private int type; + private String title; + private String href; + private User authorUser; + private String favDate; + private int favCount; + private String body; + private int commentCount; + private boolean favorite; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getHref() { + return href; + } + + public void setHref(String href) { + this.href = href; + } + + public User getAuthorUser() { + return authorUser; + } + + public void setAuthorUser(User authorUser) { + this.authorUser = authorUser; + } + + public String getFavDate() { + return favDate; + } + + public void setFavDate(String favDate) { + this.favDate = favDate; + } + + public int getFavCount() { + return favCount; + } + + public void setFavCount(int favCount) { + this.favCount = favCount; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + public int getCommentCount() { + return commentCount; + } + + public void setCommentCount(int commentCount) { + this.commentCount = commentCount; + } + + public boolean isFavorite() { + return favorite; + } + + public void setFavorite(boolean favorite) { + this.favorite = favorite; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/Event.java b/app/src/main/java/net/oschina/app/improve/bean/Event.java new file mode 100644 index 0000000000000000000000000000000000000000..8d3a681092787cba2269cadc0ba95bcf6969bff3 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/Event.java @@ -0,0 +1,107 @@ +package net.oschina.app.improve.bean; + +/** + * Created by huanghaibin + * on 16-5-25. + */ +public class Event extends PrimaryBean { + public static final int STATUS_END = 1; + public static final int STATUS_ING = 2; + public static final int STATUS_SING_UP = 3; + + public static final int EVENT_TYPE_OSC = 1; + public static final int EVENT_TYPE_TEC = 2; + public static final int EVENT_TYPE_OTHER = 3; + public static final int EVENT_TYPE_OUTSIDE = 4; + + protected int applyCount; + protected int status; + protected int type; + protected String title; + protected String body; + protected String img; + protected String startDate; + protected String endDate; + protected String pubDate; + protected String href; + + public int getApplyCount() { + return applyCount; + } + + public void setApplyCount(int applyCount) { + this.applyCount = applyCount; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + public String getImg() { + return img; + } + + public void setImg(String img) { + this.img = img; + } + + public String getStartDate() { + return startDate; + } + + public void setStartDate(String startDate) { + this.startDate = startDate; + } + + public String getEndDate() { + return endDate; + } + + public void setEndDate(String endDate) { + this.endDate = endDate; + } + + public String getPubDate() { + return pubDate; + } + + public void setPubDate(String pubDate) { + this.pubDate = pubDate; + } + + public String getHref() { + return href; + } + + public void setHref(String href) { + this.href = href; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/EventDetail.java b/app/src/main/java/net/oschina/app/improve/bean/EventDetail.java new file mode 100644 index 0000000000000000000000000000000000000000..fdd2dc873c1b1b956c5730a0d173955d1a5498c4 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/EventDetail.java @@ -0,0 +1,144 @@ +package net.oschina.app.improve.bean; + +/** + * Created by huanghaibin + * on 16-6-13. + */ +public class EventDetail extends Event { + public static final int APPLY_STATUS_UN_SIGN = -1; + public static final int APPLY_STATUS_AUDIT = 0; + public static final int APPLY_STATUS_CONFIRMED = 1; + public static final int APPLY_STATUS_PRESENTED = 2; + public static final int APPLY_STATUS_CANCELED = 3; + public static final int APPLY_STATUS_REFUSED = 4; + + private String author; + private int authorId; + private String authorPortrait; + private int commentCount; + private int viewCount; + private String spot; + private String location; + private String city; + private String costDesc; + private boolean favorite; + private EventRemark remark; + private int applyStatus; + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public int getAuthorId() { + return authorId; + } + + public void setAuthorId(int authorId) { + this.authorId = authorId; + } + + public String getAuthorPortrait() { + return authorPortrait; + } + + public void setAuthorPortrait(String authorPortrait) { + this.authorPortrait = authorPortrait; + } + + public int getCommentCount() { + return commentCount; + } + + public void setCommentCount(int commentCount) { + this.commentCount = commentCount; + } + + public int getViewCount() { + return viewCount; + } + + public void setViewCount(int viewCount) { + this.viewCount = viewCount; + } + + public String getSpot() { + return spot; + } + + public void setSpot(String spot) { + this.spot = spot; + } + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getCostDesc() { + return costDesc; + } + + public void setCostDesc(String costDesc) { + this.costDesc = costDesc; + } + + public boolean isFavorite() { + return favorite; + } + + public void setFavorite(boolean favorite) { + this.favorite = favorite; + } + + public EventRemark getRemark() { + return remark; + } + + public void setRemark(EventRemark remark) { + this.remark = remark; + } + + public int getApplyStatus() { + return applyStatus; + } + + public void setApplyStatus(int applyStatus) { + this.applyStatus = applyStatus; + } + + public static class EventRemark { + private String tip; + private String select; + + public String getTip() { + return tip; + } + + public void setTip(String tip) { + this.tip = tip; + } + + public String getSelect() { + return select; + } + + public void setSelect(String select) { + this.select = select; + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/EventSignin.java b/app/src/main/java/net/oschina/app/improve/bean/EventSignin.java new file mode 100644 index 0000000000000000000000000000000000000000..e0e08014ed47f42e27569bebb5880fb1b860424c --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/EventSignin.java @@ -0,0 +1,59 @@ +package net.oschina.app.improve.bean; + +import java.io.Serializable; + +/** + * Created by fei + * on 2016/12/1. + * desc: 活动签到bean + */ + +public class EventSignin implements Serializable { + + private int optStatus; //1: 成功 2: 活动进行中未报名 3: 活动已结束/活动报名已截止 4: 已签到 + private String message; //1.您是开源软件作者,本次活动免费~ 2.需缴纳50元!(金额由活动决定)3.未报名,不可签到 4.活动已结束/活动报名已经截止 5已签到 + private int cost; //缴纳金额(单位分) + private String href; //分享推广的链接 + + public int getOptStatus() { + return optStatus; + } + + public void setOptStatus(int optStatus) { + this.optStatus = optStatus; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public int getCost() { + return cost; + } + + public void setCost(int cost) { + this.cost = cost; + } + + public String getHref() { + return href; + } + + public void setHref(String href) { + this.href = href; + } + + @Override + public String toString() { + return "EventSignin{" + + "optStatus=" + optStatus + + ", message='" + message + '\'' + + ", cost=" + cost + + ", href='" + href + '\'' + + '}'; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/Mention.java b/app/src/main/java/net/oschina/app/improve/bean/Mention.java new file mode 100644 index 0000000000000000000000000000000000000000..2ee972d9ff676b88b28d1e276b2692d2d3990588 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/Mention.java @@ -0,0 +1,77 @@ +package net.oschina.app.improve.bean; + +import net.oschina.app.improve.bean.simple.Author; +import net.oschina.app.improve.bean.simple.Origin; + +import java.io.Serializable; + +/** + * AT我的 + * Created by huanghaibin_dev + * on 2016/8/16. + */ +public class Mention implements Serializable { + private long id; + private String content; + private String pubDate; + private Author author; + private Origin origin; + private int appClient; + private int commentCount; + + public int getAppClient() { + return appClient; + } + + public void setAppClient(int appClient) { + this.appClient = appClient; + } + + public int getCommentCount() { + return commentCount; + } + + public void setCommentCount(int commentCount) { + this.commentCount = commentCount; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getPubDate() { + return pubDate; + } + + public void setPubDate(String pubDate) { + this.pubDate = pubDate; + } + + public Author getAuthor() { + return author; + } + + public void setAuthor(Author author) { + this.author = author; + } + + public Origin getOrigin() { + return origin; + } + + public void setOrigin(Origin origin) { + this.origin = origin; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/Message.java b/app/src/main/java/net/oschina/app/improve/bean/Message.java new file mode 100644 index 0000000000000000000000000000000000000000..b1858042c37eb05bcc44c1c8f933d874082eab3a --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/Message.java @@ -0,0 +1,77 @@ +package net.oschina.app.improve.bean; + +import java.io.Serializable; + +/** + * 私信 + * Created by huanghaibin_dev + * on 2016/8/16. + */ +public class Message implements Serializable { + public static final int TYPE_TEXT = 1; + public static final int TYPE_IMAGE = 3; + public static final int TYPE_FILE = 5; + private long id; + private String content; + private String pubDate; + private int type; + private String resource; + private User sender; + private User receiver; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getPubDate() { + return pubDate; + } + + public void setPubDate(String pubDate) { + this.pubDate = pubDate; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public String getResource() { + return resource; + } + + public void setResource(String resource) { + this.resource = resource; + } + + public User getSender() { + return sender; + } + + public void setSender(User sender) { + this.sender = sender; + } + + public User getReceiver() { + return receiver; + } + + public void setReceiver(User receiver) { + this.receiver = receiver; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/News.java b/app/src/main/java/net/oschina/app/improve/bean/News.java new file mode 100644 index 0000000000000000000000000000000000000000..d3346a512828dbc36712c04ca49665cecfff6482 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/News.java @@ -0,0 +1,99 @@ +package net.oschina.app.improve.bean; + +/** + * Created by huanghaibin + * on 16-5-25. + */ +public class News extends PrimaryBean { + + public static final int TYPE_HREF = 0; + public static final int TYPE_SOFTWARE = 1; + public static final int TYPE_QUESTION = 2; + public static final int TYPE_BLOG = 3; + public static final int TYPE_TRANSLATE = 4; + public static final int TYPE_EVENT = 5; + public static final int TYPE_NEWS = 6; + public static final int TYPE_FIND_PERSON = 11; + + protected int commentCount; + protected int type; + protected boolean recommend; + protected String title; + protected String body; + protected String author; + protected String href; + protected String pubDate; + protected int viewCount; + + public String getPubDate() { + return pubDate; + } + + public void setPubDate(String pubDate) { + this.pubDate = pubDate; + } + + public int getCommentCount() { + return commentCount; + } + + public void setCommentCount(int commentCount) { + this.commentCount = commentCount; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public boolean isRecommend() { + return recommend; + } + + public void setRecommend(boolean recommend) { + this.recommend = recommend; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getHref() { + return href; + } + + public void setHref(String href) { + this.href = href; + } + + public int getViewCount() { + return viewCount; + } + + public void setViewCount(int viewCount) { + this.viewCount = viewCount; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/NewsDetail.java b/app/src/main/java/net/oschina/app/improve/bean/NewsDetail.java new file mode 100644 index 0000000000000000000000000000000000000000..55774e6042736d0304135cad768bdbbd64728e92 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/NewsDetail.java @@ -0,0 +1,94 @@ +package net.oschina.app.improve.bean; + +import com.google.gson.annotations.Expose; + +import net.oschina.app.improve.bean.comment.Comment; +import net.oschina.app.improve.bean.simple.About; +import net.oschina.app.improve.bean.simple.UserRelation; + +import java.util.List; + +/** + * Created by fei on 2016/6/13. + * desc: + */ +public class NewsDetail extends News { + + private boolean favorite; + private long authorId; + private String authorPortrait; + private List abouts; + private Software software; + @Expose + private UserRelation userRelation; + @Expose + private List comments; + + public boolean isFavorite() { + return favorite; + } + + public void setFavorite(boolean favorite) { + this.favorite = favorite; + } + + @Override + public String getHref() { + return href; + } + + @Override + public void setHref(String href) { + this.href = href; + } + + public long getAuthorId() { + return authorId; + } + + public void setAuthorId(long authorId) { + this.authorId = authorId; + } + + public String getAuthorPortrait() { + return authorPortrait; + } + + public void setAuthorPortrait(String authorPortrait) { + this.authorPortrait = authorPortrait; + } + + public List getAbouts() { + return abouts; + } + + public void setAbouts(List abouts) { + this.abouts = abouts; + } + + public Software getSoftware() { + return software; + } + + public void setSoftware(Software software) { + this.software = software; + } + + + public UserRelation getUserRelation() { + return userRelation; + } + + public void setUserRelation(UserRelation userRelation) { + this.userRelation = userRelation; + } + + public List getComments() { + return comments; + } + + public void setComments(List comments) { + this.comments = comments; + } + +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/PrimaryBean.java b/app/src/main/java/net/oschina/app/improve/bean/PrimaryBean.java new file mode 100644 index 0000000000000000000000000000000000000000..d60110315b9f89ba9d797164bc4488b867fc6c5e --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/PrimaryBean.java @@ -0,0 +1,21 @@ +package net.oschina.app.improve.bean; + +import java.io.Serializable; + +/** + * Created by qiujuer + * on 2016/11/22. + *

    + * 主要值 + */ +public class PrimaryBean implements Serializable { + private long id; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/Question.java b/app/src/main/java/net/oschina/app/improve/bean/Question.java new file mode 100644 index 0000000000000000000000000000000000000000..efaaea67faceb9f72d56c88a8e87b46f05750841 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/Question.java @@ -0,0 +1,80 @@ +package net.oschina.app.improve.bean; + +/** + * Created by fei on 2016/5/24. + * desc: question bean + */ +public class Question extends PrimaryBean { + private String title; + private String body; + private String author; + private long authorId; + private String authorPortrait; //用户头像 + private String pubDate; //发布时间 + private int commentCount; //评论次数 + private int viewCount; //浏览次数 + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public long getAuthorId() { + return authorId; + } + + public void setAuthorId(long authorId) { + this.authorId = authorId; + } + + public String getAuthorPortrait() { + return authorPortrait; + } + + public void setAuthorPortrait(String authorPortrait) { + this.authorPortrait = authorPortrait; + } + + public String getPubDate() { + return pubDate; + } + + public void setPubDate(String pubDate) { + this.pubDate = pubDate; + } + + public int getCommentCount() { + return commentCount; + } + + public void setCommentCount(int commentCount) { + this.commentCount = commentCount; + } + + public int getViewCount() { + return viewCount; + } + + public void setViewCount(int viewCount) { + this.viewCount = viewCount; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/QuestionDetail.java b/app/src/main/java/net/oschina/app/improve/bean/QuestionDetail.java new file mode 100644 index 0000000000000000000000000000000000000000..6bb9a8be64bc78cf57bbd5ca44102ccbaf5bb84f --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/QuestionDetail.java @@ -0,0 +1,39 @@ +package net.oschina.app.improve.bean; + +import java.util.List; + +/** + * 问答详情bean + */ +public class QuestionDetail extends Question { + + private boolean favorite; + private String href; + private List tags; + + public boolean isFavorite() { + return favorite; + } + + public void setFavorite(boolean favorite) { + this.favorite = favorite; + } + + public String getHref() { + return href; + } + + public void setHref(String href) { + this.href = href; + } + + + public List getTags() { + return tags; + } + + public void setTags(List tags) { + this.tags = tags; + } +} + diff --git a/app/src/main/java/net/oschina/app/improve/bean/SignUpEventOptions.java b/app/src/main/java/net/oschina/app/improve/bean/SignUpEventOptions.java new file mode 100644 index 0000000000000000000000000000000000000000..6058b9805692a7117cb08c02adc5abcebcd7b553 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/SignUpEventOptions.java @@ -0,0 +1,113 @@ +package net.oschina.app.improve.bean; + +import java.io.Serializable; +import java.util.List; + +/** + * Created by haibin + * on 2016/12/5. + */ + +public class SignUpEventOptions implements Serializable { + public static final int FORM_TYPE_TEXT = 0; + public static final int FORM_TYPE_TEXT_AREA = 1; + public static final int FORM_TYPE_SELECT = 2; + public static final int FORM_TYPE_CHECK_BOX = 3; + public static final int FORM_TYPE_RADIO = 4; + public static final int FORM_TYPE_EMAIL = 5; + public static final int FORM_TYPE_DATE = 6; + public static final int FORM_TYPE_MOBILE = 7; + public static final int FORM_TYPE_NUMBER = 8; + public static final int FORM_TYPE_URL = 9; + + private String key; + private String value;//用户输入的参数 + private List selectList;//用户多选的参数 + private int keyType; + private int formType; + private String label; + private String option; + private String optionStatus; + private String defaultValue; + private boolean required; + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getValue() { + return value; + } + + public List getSelectList() { + return selectList; + } + + public void setSelectList(List selectList) { + this.selectList = selectList; + } + + public void setValue(String value) { + this.value = value; + } + + public int getKeyType() { + return keyType; + } + + public void setKeyType(int keyType) { + this.keyType = keyType; + } + + public int getFormType() { + return formType; + } + + public void setFormType(int formType) { + this.formType = formType; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getOption() { + return option; + } + + public void setOption(String option) { + this.option = option; + } + + public String getOptionStatus() { + return optionStatus; + } + + public void setOptionStatus(String optionStatus) { + this.optionStatus = optionStatus; + } + + public String getDefaultValue() { + return defaultValue; + } + + public void setDefaultValue(String defaultValue) { + this.defaultValue = defaultValue; + } + + public boolean isRequired() { + return required; + } + + public void setRequired(boolean required) { + this.required = required; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/Software.java b/app/src/main/java/net/oschina/app/improve/bean/Software.java new file mode 100644 index 0000000000000000000000000000000000000000..d44983e787b281357bd90c7b1554f0d99d03abdb --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/Software.java @@ -0,0 +1,27 @@ +package net.oschina.app.improve.bean; + +/** + * Created by fei on 2016/6/20. + * desc: + */ +public class Software extends PrimaryBean { + private String name; + private String href; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getHref() { + return href; + } + + public void setHref(String href) { + this.href = href; + } + +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/SoftwareDetail.java b/app/src/main/java/net/oschina/app/improve/bean/SoftwareDetail.java new file mode 100644 index 0000000000000000000000000000000000000000..644d5a34c29bfaa13e9352a2ab1a1dd13008bddb --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/SoftwareDetail.java @@ -0,0 +1,220 @@ +package net.oschina.app.improve.bean; + +import net.oschina.app.improve.bean.simple.About; + +import java.util.List; + +/** + * Created by fei on 2016/6/20. + * desc: + */ +public class SoftwareDetail extends Software { + + private String extName; //软件别名 + private String logo;//logo,有null的情况哦 + private String body; //软件资讯内容 + private String author;//发布者 + private long authorId;//发布者id + private String authorPortrait;//用户头像url + private String license;//软件license信息 + private String homePage;//首页 + private String document;//文档 + private String download;//下载地址 + private String language;//开发语言 + private String supportOS;//支持平台 + private String collectionDate; //收录时间 + private String pubDate;//发布时间 + private int commentCount; //评论量,实际是动弹量 + private int viewCount;//浏览量 + private boolean favorite;//是否收藏 + private boolean recommend;//是否推荐 + private String identification; //唯一标示 + private List abouts; //相关推荐 + + public String getExtName() { + return extName; + } + + public void setExtName(String extName) { + this.extName = extName; + } + + public String getLogo() { + return logo; + } + + public void setLogo(String logo) { + this.logo = logo; + } + + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public long getAuthorId() { + return authorId; + } + + public void setAuthorId(long authorId) { + this.authorId = authorId; + } + + public String getAuthorPortrait() { + return authorPortrait; + } + + public void setAuthorPortrait(String authorPortrait) { + this.authorPortrait = authorPortrait; + } + + public String getLicense() { + return license; + } + + public void setLicense(String license) { + this.license = license; + } + + public String getHomePage() { + return homePage; + } + + public void setHomePage(String homePage) { + this.homePage = homePage; + } + + public String getDocument() { + return document; + } + + public void setDocument(String document) { + this.document = document; + } + + public String getDownload() { + return download; + } + + public void setDownload(String download) { + this.download = download; + } + + public String getLanguage() { + return language; + } + + public void setLanguage(String language) { + this.language = language; + } + + public String getSupportOS() { + return supportOS; + } + + public void setSupportOS(String supportOS) { + this.supportOS = supportOS; + } + + public String getCollectionDate() { + return collectionDate; + } + + public void setCollectionDate(String collectionDate) { + this.collectionDate = collectionDate; + } + + public String getPubDate() { + return pubDate; + } + + public void setPubDate(String pubDate) { + this.pubDate = pubDate; + } + + public int getCommentCount() { + return commentCount; + } + + public void setCommentCount(int commentCount) { + this.commentCount = commentCount; + } + + public int getViewCount() { + return viewCount; + } + + public void setViewCount(int viewCount) { + this.viewCount = viewCount; + } + + public boolean isFavorite() { + return favorite; + } + + public void setFavorite(boolean favorite) { + this.favorite = favorite; + } + + public boolean isRecommend() { + return recommend; + } + + public void setRecommend(boolean recommend) { + this.recommend = recommend; + } + + public List getAbouts() { + return abouts; + } + + public void setAbouts(List abouts) { + this.abouts = abouts; + } + + public String getIdentification() { + return identification; + } + + public void setIdentification(String identification) { + this.identification = identification; + } + + @Override + public String toString() { + return "SoftwareDetail{" + + "extName='" + extName + '\'' + + ", logo='" + logo + '\'' + + ", body='" + body + '\'' + + ", author='" + author + '\'' + + ", authorId=" + authorId + + ", authorPortrait='" + authorPortrait + '\'' + + ", license='" + license + '\'' + + ", homePage='" + homePage + '\'' + + ", document='" + document + '\'' + + ", download='" + download + '\'' + + ", language='" + language + '\'' + + ", supportOS='" + supportOS + '\'' + + ", collectionDate='" + collectionDate + '\'' + + ", pubDate='" + pubDate + '\'' + + ", commentCount=" + commentCount + + ", viewCount=" + viewCount + + ", favorite=" + favorite + + ", recommend=" + recommend + + ", identification='" + identification + '\'' + + ", abouts=" + abouts + + '}'; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/SubBean.java b/app/src/main/java/net/oschina/app/improve/bean/SubBean.java new file mode 100644 index 0000000000000000000000000000000000000000..1bddeb77be5050cfb787aa0a8cdf60dd1f19dbb7 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/SubBean.java @@ -0,0 +1,218 @@ +package net.oschina.app.improve.bean; + +import net.oschina.app.improve.bean.simple.About; +import net.oschina.app.improve.bean.simple.Author; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +/** + * Created by haibin + * on 2016/10/26. + */ + +public class SubBean implements Serializable { + private String cacheKey; + + private long id; + private String title; + private String body; + private String pubDate; + private String href; + private int type; + private Author author; + private Image image; + private Map extra; + private String[] tags; + private Statistics statistics; + private List abouts; + + public List getAbouts() { + return abouts; + } + + public void setAbouts(List abouts) { + this.abouts = abouts; + } + + public boolean isOriginal() { + if (tags != null) { + for (String tag : tags) { + if ("original".equalsIgnoreCase(tag)) { + return true; + } + } + } + return false; + } + + public boolean isAD() { + if (tags != null) { + for (String tag : tags) { + if ("ad".equalsIgnoreCase(tag)) { + return true; + } + } + } + return false; + } + + public boolean isStick() { + if (tags != null) { + for (String tag : tags) { + if ("stick".equalsIgnoreCase(tag)) { + return true; + } + } + } + return false; + } + + public boolean isRecommend() { + if (tags != null) { + for (String tag : tags) { + if ("recommend".equalsIgnoreCase(tag)) { + return true; + } + } + } + return false; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + public String getPubDate() { + return pubDate; + } + + public void setPubDate(String pubDate) { + this.pubDate = pubDate; + } + + public String getHref() { + return href; + } + + public void setHref(String href) { + this.href = href; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public Author getAuthor() { + return author; + } + + public void setAuthor(Author author) { + this.author = author; + } + + public Image getImage() { + return image; + } + + public void setImage(Image image) { + this.image = image; + } + + public Map getExtra() { + return extra; + } + + public void setExtra(Map extra) { + this.extra = extra; + } + + public String[] getTags() { + return tags; + } + + public void setTags(String[] tags) { + this.tags = tags; + } + + public Statistics getStatistics() { + return statistics; + } + + public void setStatistics(Statistics statistics) { + this.statistics = statistics; + } + + public String getKey() { + if (cacheKey == null) + cacheKey = String.format("t:%s,id:%s", getType(), getId() == 0 ? getHref().hashCode() : getId()); + return cacheKey; + } + + public static class Image implements Serializable { + private int type; + private String[] href; + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public String[] getHref() { + return href; + } + + public void setHref(String[] href) { + this.href = href; + } + } + + public static class Statistics implements Serializable { + private int comment; + private int view; + + public int getComment() { + return comment; + } + + public void setComment(int comment) { + this.comment = comment; + } + + public int getView() { + return view; + } + + public void setView(int view) { + this.view = view; + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/SubTab.java b/app/src/main/java/net/oschina/app/improve/bean/SubTab.java new file mode 100644 index 0000000000000000000000000000000000000000..c6a110649c6cee35db65cd30b0fa773c670e349d --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/SubTab.java @@ -0,0 +1,179 @@ +package net.oschina.app.improve.bean; + +import java.io.Serializable; + +/** + * 分栏Model + * Created by thanatosx + * on 16/10/26. + */ +public class SubTab implements Serializable { + + public static final String TAG_NEW = "new"; + public static final String TAG_HOT = "hot"; + + public static final int BANNER_CATEGORY_NEWS = 1; + public static final int BANNER_CATEGORY_EVENT = 2; + + private String token; + private String name; + private boolean fixed; + private boolean needLogin; + private String tag; + private int type; + private int subtype; + private int order; + private String href; + private Banner banner; + private boolean isActived; + + + public class Banner implements Serializable { + private int catalog; + private String href; + + public int getCatalog() { + return catalog; + } + + public void setCatalog(int catalog) { + this.catalog = catalog; + } + + public String getHref() { + return href; + } + + public void setHref(String href) { + this.href = href; + } + + @Override + public String toString() { + return "Banner{" + + "catalog=" + catalog + + ", href='" + href + '\'' + + '}'; + } + } + + @Override + public int hashCode() { + return this.token == null ? 0 : this.token.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj != null && obj instanceof SubTab) { + SubTab tab = (SubTab) obj; + if (tab.getToken() == null) return false; + if (this.token == null) return false; + return tab.getToken().equals(this.token); + } + return false; + } + + public boolean isActived() { + return isActived; + } + + public void setActived(boolean actived) { + isActived = actived; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public boolean isFixed() { + return fixed; + } + + public void setFixed(boolean fixed) { + this.fixed = fixed; + } + + public boolean isNeedLogin() { + return needLogin; + } + + public void setNeedLogin(boolean needLogin) { + this.needLogin = needLogin; + } + + public String getTag() { + return tag; + } + + public void setTag(String tag) { + this.tag = tag; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public int getSubtype() { + return subtype; + } + + public void setSubtype(int subtype) { + this.subtype = subtype; + } + + public int getOrder() { + return order; + } + + public void setOrder(int order) { + this.order = order; + } + + public String getHref() { + return href; + } + + public void setHref(String href) { + this.href = href; + } + + public Banner getBanner() { + return banner; + } + + public void setBanner(Banner banner) { + this.banner = banner; + } + + @Override + public String toString() { + return "SubTab{" + + "token='" + token + '\'' + + ", name='" + name + '\'' + + ", fixed=" + fixed + + ", needLogin=" + needLogin + + ", tag='" + tag + '\'' + + ", type=" + type + + ", subtype=" + subtype + + ", order=" + order + + ", href='" + href + '\'' + + ", banner=" + banner + + '}'; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/TranslationDetail.java b/app/src/main/java/net/oschina/app/improve/bean/TranslationDetail.java new file mode 100644 index 0000000000000000000000000000000000000000..a70dbabaa5e13dec773f7b2b87de1191d7fb454c --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/TranslationDetail.java @@ -0,0 +1,116 @@ +package net.oschina.app.improve.bean; + +/** + * Created by fei on 2016/6/28. + * desc: question bean + */ +public class TranslationDetail extends PrimaryBean { + private String title; + private String originlTitle; //原始文章名称,比如英文的 + private String body; + private String author; + private long authorId; + private String authorPortrait; //用户头像 + private int authorRelation; //与翻译作者的关系 + private String pubDate; //发布时间 + private int commentCount; //评论次数 + private int viewCount; //浏览次数 + private String href; + private boolean favorite; + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getOriginlTitle() { + return originlTitle; + } + + public void setOriginlTitle(String originlTitle) { + this.originlTitle = originlTitle; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public long getAuthorId() { + return authorId; + } + + public void setAuthorId(long authorId) { + this.authorId = authorId; + } + + public String getAuthorPortrait() { + return authorPortrait; + } + + public void setAuthorPortrait(String authorPortrait) { + this.authorPortrait = authorPortrait; + } + + public int getAuthorRelation() { + return authorRelation; + } + + public void setAuthorRelation(int authorRelation) { + this.authorRelation = authorRelation; + } + + public String getPubDate() { + return pubDate; + } + + public void setPubDate(String pubDate) { + this.pubDate = pubDate; + } + + public int getCommentCount() { + return commentCount; + } + + public void setCommentCount(int commentCount) { + this.commentCount = commentCount; + } + + public int getViewCount() { + return viewCount; + } + + public void setViewCount(int viewCount) { + this.viewCount = viewCount; + } + + public boolean isFavorite() { + return favorite; + } + + public void setFavorite(boolean favorite) { + this.favorite = favorite; + } + + public String getHref() { + return href; + } + + public void setHref(String href) { + this.href = href; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/Tweet.java b/app/src/main/java/net/oschina/app/improve/bean/Tweet.java new file mode 100644 index 0000000000000000000000000000000000000000..6e6d8840a6bf9517dafb0e5397f592d19d85ffbc --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/Tweet.java @@ -0,0 +1,325 @@ +package net.oschina.app.improve.bean; + +import android.text.TextUtils; + +import net.oschina.app.improve.bean.simple.About; +import net.oschina.app.improve.bean.simple.Author; +import net.oschina.common.utils.CollectionUtil; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Created by huanghaibin_dev + * on 2016/7/18. + */ +public class Tweet implements Serializable { + private long id; + private String content; + private int appClient; + private int commentCount; + private int likeCount; + private boolean liked; + private String pubDate; + private Author author; + private Code code; + private String href; + private Audio[] audio; + private Image[] images; + private Statistics statistics; + private About about; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public int getAppClient() { + return appClient; + } + + public void setAppClient(int appClient) { + this.appClient = appClient; + } + + public int getCommentCount() { + return commentCount; + } + + public void setCommentCount(int commentCount) { + this.commentCount = commentCount; + } + + public String getHref() { + return href; + } + + public void setHref(String href) { + this.href = href; + } + + public int getLikeCount() { + return likeCount; + } + + public void setLikeCount(int likeCount) { + this.likeCount = likeCount; + } + + public boolean isLiked() { + return liked; + } + + public void setLiked(boolean liked) { + this.liked = liked; + } + + public String getPubDate() { + return pubDate; + } + + public void setPubDate(String pubDate) { + this.pubDate = pubDate; + } + + public Author getAuthor() { + return author; + } + + public void setAuthor(Author author) { + this.author = author; + } + + public Code getCode() { + return code; + } + + public void setCode(Code code) { + this.code = code; + } + + public Audio[] getAudio() { + return audio; + } + + public void setAudio(Audio[] audio) { + this.audio = audio; + } + + public Image[] getImages() { + return images; + } + + public void setImages(Image[] images) { + this.images = images; + } + + public About getAbout() { + return about; + } + + public void setAbout(About about) { + this.about = about; + } + + public Statistics getStatistics() { + return statistics; + } + + public void setStatistics(Statistics statistics) { + this.statistics = statistics; + } + + public static class Code implements Serializable { + private String brush; + private String content; + + public String getBrush() { + return brush; + } + + public void setBrush(String brush) { + this.brush = brush; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + } + + public static class Audio implements Serializable { + private String href; + private long timeSpan; + + public String getHref() { + return href; + } + + public void setHref(String href) { + this.href = href; + } + + public long getTimeSpan() { + return timeSpan; + } + + public void setTimeSpan(long timeSpan) { + this.timeSpan = timeSpan; + } + } + + public static class Image implements Serializable { + private String thumb; + private String href; + private String name; + private int type; + private int w; + private int h; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public String getThumb() { + return thumb; + } + + public void setThumb(String thumb) { + this.thumb = thumb; + } + + public String getHref() { + return href; + } + + public void setHref(String href) { + this.href = href; + } + + public int getW() { + return w; + } + + public void setW(int w) { + this.w = w; + } + + public int getH() { + return h; + } + + public void setH(int h) { + this.h = h; + } + + public static Image create(String href) { + Image image = new Image(); + image.thumb = href; + image.href = href; + return image; + } + + public static String[] getImagePath(Image[] images) { + if (images == null || images.length == 0) + return null; + + List paths = new ArrayList<>(); + for (Image image : images) { + if (check(image)) + paths.add(image.href); + } + + return CollectionUtil.toArray(paths, String.class); + } + + public static boolean check(Image image) { + return image != null + && !TextUtils.isEmpty(image.getThumb()) + && !TextUtils.isEmpty(image.getHref()); + } + } + + public static class Statistics implements Serializable { + private int comment; + private int transmit; + private int like; + + public int getLike() { + return like; + } + + public void setLike(int like) { + this.like = like; + } + + public int getComment() { + return comment; + } + + public void setComment(int comment) { + this.comment = comment; + } + + public int getTransmit() { + return transmit; + } + + public void setTransmit(int transmit) { + this.transmit = transmit; + } + } + + @Override + public String toString() { + return "Tweet{" + + "id=" + id + + ", content='" + content + '\'' + + ", appClient=" + appClient + + ", commentCount=" + commentCount + + ", likeCount=" + likeCount + + ", liked=" + liked + + ", pubDate='" + pubDate + '\'' + + ", author=" + author + + ", code=" + code + + ", audio=" + Arrays.toString(audio) + + ", images=" + Arrays.toString(images) + + '}'; + } + + @Override + public boolean equals(Object o) { + if (o != null && o instanceof Tweet) { + return ((Tweet) o).getId() == id; + } + return false; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/User.java b/app/src/main/java/net/oschina/app/improve/bean/User.java new file mode 100644 index 0000000000000000000000000000000000000000..50587fc106c566200d238fb10c0e231f7eb46fbf --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/User.java @@ -0,0 +1,289 @@ +package net.oschina.app.improve.bean; + +import java.io.Serializable; + +/** + * 用户信息类 + */ +public class User implements Serializable { + public static final int RELATION_TYPE_BOTH = 0x01;// 双方互为粉丝 + public static final int RELATION_TYPE_ONLY_FANS_HIM = 0x02;// 你单方面关注他 + public static final int RELATION_TYPE_ONLY_FANS_ME = 0x03;// 只有他关注我 + public static final int RELATION_TYPE_NULL = 0x04;// 互不关注 + + public static final int GENDER_MALE = 1; // 男 + public static final int GENDER_FEMALE = 2; // 女 + + // Base + private long id; + private String name; + private String portrait; + // More + private int gender; + private String desc; + private int relation; + //个性后缀 + private String suffix; + private More more; + private Statistics statistics; + // 本地缓存多余信息 + private String cookie; + + public User() { + more = new More(); + statistics = new Statistics(); + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPortrait() { + return portrait; + } + + public void setPortrait(String portrait) { + this.portrait = portrait; + } + + public String getSuffix() { + return suffix; + } + + public void setSuffix(String suffix) { + this.suffix = suffix; + } + + public int getGender() { + return gender; + } + + public void setGender(int gender) { + this.gender = gender; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + + public int getRelation() { + return relation; + } + + public void setRelation(int relation) { + this.relation = relation; + } + + public More getMore() { + return more; + } + + public void setMore(More more) { + this.more = more; + } + + public Statistics getStatistics() { + return statistics; + } + + public void setStatistics(Statistics statistics) { + this.statistics = statistics; + } + + public String getCookie() { + return cookie; + } + + public void setCookie(String cookie) { + this.cookie = cookie; + } + + @Override + public String toString() { + return "User{" + "id=" + id + + ", name='" + name + '\'' + + ", portrait='" + portrait + '\'' + + "gender=" + gender + + ", desc='" + desc + '\'' + + ", relation=" + relation + + ", suffix='" + suffix + '\'' + + ", more=" + more + + ", statistics=" + statistics + + '}'; + } + + + public static class More implements Serializable { + private String joinDate; + private String city; + private String expertise; + private String platform; + private String company; + private String position; + + public String getJoinDate() { + return joinDate; + } + + public void setJoinDate(String joinDate) { + this.joinDate = joinDate; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getExpertise() { + return expertise; + } + + public void setExpertise(String expertise) { + this.expertise = expertise; + } + + public String getPlatform() { + return platform; + } + + public void setPlatform(String platform) { + this.platform = platform; + } + + public String getCompany() { + return company; + } + + public void setCompany(String company) { + this.company = company; + } + + public String getPosition() { + return position; + } + + public void setPosition(String position) { + this.position = position; + } + + @Override + public String toString() { + return "More{" + + "joinDate='" + joinDate + '\'' + + ", city='" + city + '\'' + + ", expertise='" + expertise + '\'' + + ", platform='" + platform + '\'' + + ", company='" + company + '\'' + + ", position='" + position + '\'' + + '}'; + } + } + + public static class Statistics implements Serializable { + private int score; + private int tweet; + private int collect; + private int fans; + private int follow; + private int blog; + private int answer; + private int discuss; + + public int getScore() { + return score; + } + + public void setScore(int score) { + this.score = score; + } + + public int getTweet() { + return tweet; + } + + public void setTweet(int tweet) { + this.tweet = tweet; + } + + public int getCollect() { + return collect; + } + + public void setCollect(int collect) { + this.collect = collect; + } + + public int getFans() { + return fans; + } + + public void setFans(int fans) { + this.fans = fans; + } + + public int getFollow() { + return follow; + } + + public void setFollow(int follow) { + this.follow = follow; + } + + public int getBlog() { + return blog; + } + + public void setBlog(int blog) { + this.blog = blog; + } + + public int getAnswer() { + return answer; + } + + public void setAnswer(int answer) { + this.answer = answer; + } + + public int getDiscuss() { + return discuss; + } + + public void setDiscuss(int discuss) { + this.discuss = discuss; + } + + @Override + public String toString() { + return "Statistics{" + + "score=" + score + + ", tweet=" + tweet + + ", collect=" + collect + + ", fans=" + fans + + ", follow=" + follow + + ", blog=" + blog + + ", answer=" + answer + + ", discuss=" + discuss + + '}'; + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/Version.java b/app/src/main/java/net/oschina/app/improve/bean/Version.java new file mode 100644 index 0000000000000000000000000000000000000000..26b9a05a6317f2dad0ac23fb87442b97b9f8397e --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/Version.java @@ -0,0 +1,65 @@ +package net.oschina.app.improve.bean; + +import java.io.Serializable; + +/** + * Created by haibin + * on 2016/10/19. + */ + +public class Version implements Serializable { + private String code; + private String name; + private String release; + private String message; + private String downloadUrl; + private String publishDate; + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getRelease() { + return release; + } + + public void setRelease(String release) { + this.release = release; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getDownloadUrl() { + return downloadUrl; + } + + public void setDownloadUrl(String downloadUrl) { + this.downloadUrl = downloadUrl; + } + + public String getPublishDate() { + return publishDate; + } + + public void setPublishDate(String publishDate) { + this.publishDate = publishDate; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/base/PageBean.java b/app/src/main/java/net/oschina/app/improve/bean/base/PageBean.java new file mode 100644 index 0000000000000000000000000000000000000000..3684109ca61e59f92801e94c2942a661db4a9376 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/base/PageBean.java @@ -0,0 +1,86 @@ +package net.oschina.app.improve.bean.base; + +import java.io.Serializable; +import java.util.List; + +/** + * Created by huanghaibin + * on 16-5-24. + */ +public class PageBean implements Serializable { + private List items; + private String nextPageToken; + private String prevPageToken; + private int requestCount; + private int responseCount; + private int totalResults; + + public List getItems() { + return items; + } + + public void setItems(List items) { + this.items = items; + } + + public String getNextPageToken() { + return nextPageToken; + } + + public void setNextPageToken(String nextPageToken) { + this.nextPageToken = nextPageToken; + } + + public String getPrevPageToken() { + return prevPageToken; + } + + public void setPrevPageToken(String prevPageToken) { + this.prevPageToken = prevPageToken; + } + + public int getRequestCount() { + return requestCount; + } + + public void setRequestCount(int requestCount) { + this.requestCount = requestCount; + } + + public int getResponseCount() { + return responseCount; + } + + public void setResponseCount(int responseCount) { + this.responseCount = responseCount; + } + + public int getTotalResults() { + return totalResults; + } + + public void setTotalResults(int totalResults) { + this.totalResults = totalResults; + } + + public static class PageInfo implements Serializable { + private int totalResults; + private int resultsPerPage; + + public int getTotalResults() { + return totalResults; + } + + public void setTotalResults(int totalResults) { + this.totalResults = totalResults; + } + + public int getResultsPerPage() { + return resultsPerPage; + } + + public void setResultsPerPage(int resultsPerPage) { + this.resultsPerPage = resultsPerPage; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/oschina/app/improve/bean/base/ResultBean.java b/app/src/main/java/net/oschina/app/improve/bean/base/ResultBean.java new file mode 100644 index 0000000000000000000000000000000000000000..5a39ec728f9d77e23908a9eab961bee312e46a69 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/base/ResultBean.java @@ -0,0 +1,65 @@ +package net.oschina.app.improve.bean.base; + +/** + * Created by huanghaibin + * on 16-5-23. + */ +public class ResultBean { + public static final int RESULT_SUCCESS = 1; + public static final int RESULT_UNKNOW = 0; + public static final int RESULT_ERROR = -1; + public static final int RESULT_NOT_FIND = 404; + public static final int RESULT_NOT_LOGIN = 201; + public static final int RESULT_TOKEN_EXPRIED = 202; + public static final int RESULT_NOT_PERMISSION = 203; + public static final int RESULT_TOKEN_ERROR = 204; + + private T result; + private int code; + private String message; + private String time; + + public T getResult() { + return result; + } + + public void setResult(T result) { + this.result = result; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getTime() { + return time; + } + + public void setTime(String time) { + this.time = time; + } + + public boolean isSuccess() { + return code == RESULT_SUCCESS && result != null; + } + + @Override + public String toString() { + return "code:" + code + + " + message:" + message + + " + time:" + time + + " + result:" + result.toString(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/comment/Comment.java b/app/src/main/java/net/oschina/app/improve/bean/comment/Comment.java new file mode 100644 index 0000000000000000000000000000000000000000..4f8eff83138d168d7a725fb9a82279b17fa7d760 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/comment/Comment.java @@ -0,0 +1,125 @@ +package net.oschina.app.improve.bean.comment; + +import net.oschina.app.improve.bean.simple.Author; + +import java.io.Serializable; +import java.util.Arrays; + +/** + * Created by fei + * on 16/11/15. + * 评论实体,适用于所有评论(不包括软件评论,软件评论实际是一条动弹) + */ +public class Comment implements Serializable { + + public static final int VOTE_STATE_DEFAULT = 0; + public static final int VOTE_STATE_UP = 1; + public static final int VOTE_STATE_DOWN = 2; + + private long id; + private Author author; + private String content; + private String pubDate; + private int appClient; + private long vote; + private int voteState; + private boolean best; + private Refer[] refer; + private Reply[] reply; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public Author getAuthor() { + return author; + } + + public void setAuthor(Author author) { + this.author = author; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getPubDate() { + return pubDate; + } + + public void setPubDate(String pubDate) { + this.pubDate = pubDate; + } + + public int getAppClient() { + return appClient; + } + + public void setAppClient(int appClient) { + this.appClient = appClient; + } + + public long getVote() { + return vote; + } + + public void setVote(long vote) { + this.vote = vote; + } + + public int getVoteState() { + return voteState; + } + + public void setVoteState(int voteState) { + this.voteState = voteState; + } + + public boolean isBest() { + return best; + } + + public void setBest(boolean best) { + this.best = best; + } + + public Refer[] getRefer() { + return refer; + } + + public void setRefer(Refer[] refer) { + this.refer = refer; + } + + public Reply[] getReply() { + return reply; + } + + public void setReply(Reply[] reply) { + this.reply = reply; + } + + @Override + public String toString() { + return "Comment{" + + "id=" + id + + ", author=" + author + + ", content='" + content + '\'' + + ", pubDate='" + pubDate + '\'' + + ", appClient=" + appClient + + ", vote=" + vote + + ", voteState=" + voteState + + ", best=" + best + + ", refer=" + Arrays.toString(refer) + + ", reply=" + Arrays.toString(reply) + + '}'; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/comment/Refer.java b/app/src/main/java/net/oschina/app/improve/bean/comment/Refer.java new file mode 100644 index 0000000000000000000000000000000000000000..69f99646f1f48848077cc3a6b8b977cea62e0ae4 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/comment/Refer.java @@ -0,0 +1,48 @@ +package net.oschina.app.improve.bean.comment; + +import java.io.Serializable; + +/** + * Created by fei + * on 2016/11/15. + * desc:评论的引用,比如对他人评论的引用 + */ + +public class Refer implements Serializable { + private String author; + private String content; + private String pubDate; + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getPubDate() { + return pubDate; + } + + public void setPubDate(String pubDate) { + this.pubDate = pubDate; + } + + @Override + public String toString() { + return "Refer{" + + "author='" + author + '\'' + + ", content='" + content + '\'' + + ", pubDate='" + pubDate + '\'' + + '}'; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/comment/Reply.java b/app/src/main/java/net/oschina/app/improve/bean/comment/Reply.java new file mode 100644 index 0000000000000000000000000000000000000000..2bc9aae1a9d2fc62cfb7cf7bad954476cf0fd4fd --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/comment/Reply.java @@ -0,0 +1,60 @@ +package net.oschina.app.improve.bean.comment; + +import net.oschina.app.improve.bean.simple.Author; + +import java.io.Serializable; + +/** + * Created by fei + * on 2016/11/15. + * desc: 对某一个引用评论的回复(评论) + */ + +public class Reply implements Serializable { + private long id; + private Author author; + private String content; + private String pubDate; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public Author getAuthor() { + return author; + } + + public void setAuthor(Author author) { + this.author = author; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getPubDate() { + return pubDate; + } + + public void setPubDate(String pubDate) { + this.pubDate = pubDate; + } + + @Override + public String toString() { + return "Reply{" + + "id=" + id + + ", author=" + author + + ", content='" + content + '\'' + + ", pubDate='" + pubDate + '\'' + + '}'; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/comment/Vote.java b/app/src/main/java/net/oschina/app/improve/bean/comment/Vote.java new file mode 100644 index 0000000000000000000000000000000000000000..66c66216086767d24ee5a3bc7e3ff600533ae41c --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/comment/Vote.java @@ -0,0 +1,39 @@ +package net.oschina.app.improve.bean.comment; + +import java.io.Serializable; + +/** + * Created by fei + * on 2016/11/18. + * desc:vote + */ + +public class Vote implements Serializable { + + private long vote; + private int voteState; + + public long getVote() { + return vote; + } + + public void setVote(long vote) { + this.vote = vote; + } + + public int getVoteState() { + return voteState; + } + + public void setVoteState(int voteState) { + this.voteState = voteState; + } + + @Override + public String toString() { + return "Vote{" + + "vote=" + vote + + ", voteState=" + voteState + + '}'; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/resource/ImageResource.java b/app/src/main/java/net/oschina/app/improve/bean/resource/ImageResource.java new file mode 100644 index 0000000000000000000000000000000000000000..229d01caaf55cd69571720f2b2eb2da2c5599a6f --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/resource/ImageResource.java @@ -0,0 +1,33 @@ +package net.oschina.app.improve.bean.resource; + +/** + * Created by JuQiu + * on 16/7/19. + */ +public class ImageResource { + private Image[] resources; + private String token; + + public Image[] getResources() { + return resources; + } + + public void setResources(Image[] resources) { + this.resources = resources; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + public static class Image { + public String name; + public String thumb; + public String href; + public String type; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/shake/ShakeNews.java b/app/src/main/java/net/oschina/app/improve/bean/shake/ShakeNews.java new file mode 100644 index 0000000000000000000000000000000000000000..073f8b8dbb36a667b5a942a1214e6ccc97ca809a --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/shake/ShakeNews.java @@ -0,0 +1,74 @@ +package net.oschina.app.improve.bean.shake; + +import java.io.Serializable; + +/** + * Created by haibin + * on 2016/10/12. + */ + +public class ShakeNews implements Serializable { + private String name; + private String detail; + private String href; + private long id; + private String img; + private String pubDate; + private int type; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDetail() { + return detail; + } + + public void setDetail(String detail) { + this.detail = detail; + } + + public String getHref() { + return href; + } + + public void setHref(String href) { + this.href = href; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getImg() { + return img; + } + + public void setImg(String img) { + this.img = img; + } + + public String getPubDate() { + return pubDate; + } + + public void setPubDate(String pubDate) { + this.pubDate = pubDate; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/shake/ShakePresent.java b/app/src/main/java/net/oschina/app/improve/bean/shake/ShakePresent.java new file mode 100644 index 0000000000000000000000000000000000000000..2dad7ecefecfba3912f1100358eafbaadf019224 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/shake/ShakePresent.java @@ -0,0 +1,38 @@ +package net.oschina.app.improve.bean.shake; + +import java.io.Serializable; + +/** + * Created by haibin + * on 2016/10/12. + */ + +public class ShakePresent implements Serializable { + private String name; + private String pic; + private String href; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPic() { + return pic; + } + + public void setPic(String pic) { + this.pic = pic; + } + + public String getHref() { + return href; + } + + public void setHref(String href) { + this.href = href; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/simple/About.java b/app/src/main/java/net/oschina/app/improve/bean/simple/About.java new file mode 100644 index 0000000000000000000000000000000000000000..85e5d6af7a9783867ca2e1f67204572d3319df63 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/simple/About.java @@ -0,0 +1,221 @@ +package net.oschina.app.improve.bean.simple; + +import android.text.TextUtils; + +import com.google.gson.annotations.Expose; + +import net.oschina.app.improve.bean.Tweet; + +import java.io.Serializable; +import java.util.Arrays; + +/** + * Created by JuQiu + * on 16/6/16. + * 相关推荐实体 + */ +public class About implements Serializable { + private long id; + private String title; + private String content; + private int type; + private String href; + private int viewCount; + private int commentCount; + private int transmitCount; + private Tweet.Image[] images; + @Expose + private long commitTweetId; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public int getCommentCount() { + return commentCount; + } + + public void setCommentCount(int commentCount) { + this.commentCount = commentCount; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public int getViewCount() { + return viewCount; + } + + public void setViewCount(int viewCount) { + this.viewCount = viewCount; + } + + public String getHref() { + return href; + } + + public void setHref(String href) { + this.href = href; + } + + public Tweet.Image[] getImages() { + return images; + } + + public void setImages(Tweet.Image[] images) { + this.images = images; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public int getTransmitCount() { + return transmitCount; + } + + public void setTransmitCount(int transmitCount) { + this.transmitCount = transmitCount; + } + + public long getCommitTweetId() { + return commitTweetId; + } + + public void setCommitTweetId(long commitTweetId) { + this.commitTweetId = commitTweetId; + } + + public static class Statistics implements Serializable { + private int comment; + private int view; + private int transmit; + + public int getComment() { + return comment; + } + + public void setComment(int comment) { + this.comment = comment; + } + + public int getView() { + return view; + } + + public void setView(int view) { + this.view = view; + } + + public int getTransmit() { + return transmit; + } + + public void setTransmit(int transmit) { + this.transmit = transmit; + } + } + + @Override + public String toString() { + return "About{" + + "id=" + id + + ", title='" + title + '\'' + + ", content='" + content + '\'' + + ", type=" + type + + ", href='" + href + '\'' + + ", viewCount=" + viewCount + + ", commentCount=" + commentCount + + ", transmitCount=" + transmitCount + + ", images=" + Arrays.toString(images) + + '}'; + } + + /** + * 检查一个About节点是否有效 + * + * @param about About + * @return True 则有效 + */ + public static boolean check(About about) { + return about != null + && !(about.id <= 0 && about.type <= 0 && TextUtils.isEmpty(about.href)); + } + + public static Share buildShare(About about) { + Share share = new Share(); + share.id = about.id; + share.type = about.type; + share.title = about.title; + share.content = about.content; + return share; + } + + public static Share buildShare(About about, long commitTweetId) { + Share share = buildShare(about); + share.commitTweetId = about.commitTweetId; + return share; + } + + public static Share buildShare(long id, int type) { + Share share = new Share(); + share.id = id; + share.type = type; + return share; + } + + /** + * 动弹分享节点 + */ + public static class Share implements Serializable { + public long id; + public int type; + public long commitTweetId; + public String title; + public String content; + public long fromTweetId; + + @Override + public String toString() { + return "Share{" + + "id=" + id + + ", type=" + type + + ", commitTweetId=" + commitTweetId + + ", title='" + title + '\'' + + ", content='" + content + '\'' + + ", fromTweetId=" + fromTweetId + + '}'; + } + } + + /** + * 检查About节点 + * + * @param share Share + * @return 返回分享节点是否正确 + */ + public static boolean check(Share share) { + return share != null && share.id > 0 && share.type >= 0; + } +} \ No newline at end of file diff --git a/app/src/main/java/net/oschina/app/improve/bean/simple/Author.java b/app/src/main/java/net/oschina/app/improve/bean/simple/Author.java new file mode 100644 index 0000000000000000000000000000000000000000..465422aab6ad8b1c25d25e2c1909b8611cc5c530 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/simple/Author.java @@ -0,0 +1,37 @@ +package net.oschina.app.improve.bean.simple; + +import java.io.Serializable; + +/** + * Created by huanghaibin_dev + * on 2016/7/18. + */ +public class Author implements Serializable { + protected long id; + protected String name; + protected String portrait; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPortrait() { + return portrait; + } + + public void setPortrait(String portrait) { + this.portrait = portrait; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/simple/Comment.java b/app/src/main/java/net/oschina/app/improve/bean/simple/Comment.java new file mode 100644 index 0000000000000000000000000000000000000000..9be843f5d113c4bb80539eb810a7cc3aaecda3c8 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/simple/Comment.java @@ -0,0 +1,91 @@ +package net.oschina.app.improve.bean.simple; + +import java.io.Serializable; + +/** + * Created by JuQiu + * on 16/6/16. + * 评论实体 + */ + +public class Comment implements Serializable { + private long id; + private long authorId; + private String author; + private String authorPortrait; + private String content; + private String pubDate; + private int appClient; + private Refer refer; + + public static class Refer implements Serializable { + public String author; + public String content; + public String pubDate; + public Refer refer; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public long getAuthorId() { + return authorId; + } + + public void setAuthorId(long authorId) { + this.authorId = authorId; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getAuthorPortrait() { + return authorPortrait; + } + + public void setAuthorPortrait(String authorPortrait) { + this.authorPortrait = authorPortrait; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getPubDate() { + return pubDate; + } + + public void setPubDate(String pubDate) { + this.pubDate = pubDate; + } + + public int getAppClient() { + return appClient; + } + + public void setAppClient(int appClient) { + this.appClient = appClient; + } + + public Refer getRefer() { + return refer; + } + + public void setRefer(Refer refer) { + this.refer = refer; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/simple/CommentEX.java b/app/src/main/java/net/oschina/app/improve/bean/simple/CommentEX.java new file mode 100644 index 0000000000000000000000000000000000000000..c5f6487534978bc55cce20091aaa4e1b5eb7a661 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/simple/CommentEX.java @@ -0,0 +1,112 @@ +package net.oschina.app.improve.bean.simple; + +import com.google.gson.annotations.SerializedName; + +import java.io.Serializable; + +/** + * Created by JuQiu + * on 16/6/16. + * 评论实体增强,适用于:问答模块 + */ +public class CommentEX extends Comment { + + public static final int VOTE_STATE_DEFAULT = 0; + public static final int VOTE_STATE_UP = 1; + public static final int VOTE_STATE_DOWN = 2; + + @SerializedName("vote") + private int voteCount; + private boolean best; + private int voteState; + private Reply[] reply; + + public static class Reply implements Serializable { + private long id; + private long authorId; + private String author; + private String content; + private String authorPortrait; + private String pubDate; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public long getAuthorId() { + return authorId; + } + + public void setAuthorId(long authorId) { + this.authorId = authorId; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getAuthorPortrait() { + return authorPortrait; + } + + public void setAuthorPortrait(String authorPortrait) { + this.authorPortrait = authorPortrait; + } + + public String getPubDate() { + return pubDate; + } + + public void setPubDate(String pubDate) { + this.pubDate = pubDate; + } + } + + public int getVoteState() { + return voteState; + } + + public void setVoteState(int voteState) { + this.voteState = voteState; + } + + public Reply[] getReply() { + return reply; + } + + public void setReply(Reply[] reply) { + this.reply = reply; + } + + public int getVoteCount() { + return voteCount; + } + + public void setVoteCount(int voteCount) { + this.voteCount = voteCount; + } + + public boolean isBest() { + return best; + } + + public void setBest(boolean best) { + this.best = best; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/simple/Origin.java b/app/src/main/java/net/oschina/app/improve/bean/simple/Origin.java new file mode 100644 index 0000000000000000000000000000000000000000..b68336ed536a9796dbe52fbd3305c9778714fb51 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/simple/Origin.java @@ -0,0 +1,56 @@ +package net.oschina.app.improve.bean.simple; + +import java.io.Serializable; + +/** + * 来源:消息:AT我 + * Created by huanghaibin_dev + * on 2016/8/16. + */ +public class Origin implements Serializable { + public static final int ORIGIN_TYPE_LINK = 0; // 链接新闻 + public static final int ORIGIN_TYPE_SOFTWARE = 1; // 软件推荐 + public static final int ORIGIN_TYPE_DISCUSS = 2; // 讨论区帖子 + public static final int ORIGIN_TYPE_BLOG = 3; // 博客 + public static final int ORIGIN_TYPE_TRANSLATION = 4; // 翻译文章 + public static final int ORIGIN_TYPE_ACTIVE = 5; // 活动类型 + public static final int ORIGIN_TYPE_NEWS = 6; // 资讯类型 + public static final int ORIGIN_TYPE_TWEETS = 100; // 动弹 + + private long id; + private String desc; + private String href; + private int type; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + + public String getHref() { + return href; + } + + public void setHref(String href) { + this.href = href; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/simple/SoftwareTweetLike.java b/app/src/main/java/net/oschina/app/improve/bean/simple/SoftwareTweetLike.java new file mode 100644 index 0000000000000000000000000000000000000000..b249086275de220157e451315d1a1cfe9a8db9db --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/simple/SoftwareTweetLike.java @@ -0,0 +1,38 @@ +package net.oschina.app.improve.bean.simple; + +import java.io.Serializable; + +/** + * Created by fei on 2016/7/19. + * desc: + */ + +public class SoftwareTweetLike implements Serializable { + + private Author author; + private boolean isLike; + + public Author getAuthor() { + return author; + } + + public void setAuthor(Author author) { + this.author = author; + } + + public boolean isLike() { + return isLike; + } + + public void setLike(boolean like) { + isLike = like; + } + + @Override + public String toString() { + return "SoftwareTweetLike{" + + "author=" + author + + ", isLike=" + isLike + + '}'; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/simple/TweetComment.java b/app/src/main/java/net/oschina/app/improve/bean/simple/TweetComment.java new file mode 100644 index 0000000000000000000000000000000000000000..355f3d29e7284a8279de0af7b63e4e0998bba825 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/simple/TweetComment.java @@ -0,0 +1,56 @@ +package net.oschina.app.improve.bean.simple; + +import java.io.Serializable; + +/** + * 动弹评论实体 + * Created by thanatos on 16/7/19. + */ +public class TweetComment implements Serializable { + + private long id; + private String content; + private String pubDate; + private int appClient; + private Author author; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getPubDate() { + return pubDate; + } + + public void setPubDate(String pubDate) { + this.pubDate = pubDate; + } + + public int getAppClient() { + return appClient; + } + + public void setAppClient(int appClient) { + this.appClient = appClient; + } + + public Author getAuthor() { + return author; + } + + public void setAuthor(Author author) { + this.author = author; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/simple/TweetLike.java b/app/src/main/java/net/oschina/app/improve/bean/simple/TweetLike.java new file mode 100644 index 0000000000000000000000000000000000000000..564f1614f049d96180cb75b32109e1d1a8a79c31 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/simple/TweetLike.java @@ -0,0 +1,35 @@ +package net.oschina.app.improve.bean.simple; + +/** + * Created by thanatos on 16/7/19. + */ +public class TweetLike { + + private String pubDate; + private Author author; + private boolean liked; + + public String getPubDate() { + return pubDate; + } + + public void setPubDate(String pubDate) { + this.pubDate = pubDate; + } + + public Author getAuthor() { + return author; + } + + public void setAuthor(Author author) { + this.author = author; + } + + public boolean isLiked() { + return liked; + } + + public void setLiked(boolean liked) { + this.liked = liked; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/simple/TweetLikeReverse.java b/app/src/main/java/net/oschina/app/improve/bean/simple/TweetLikeReverse.java new file mode 100644 index 0000000000000000000000000000000000000000..d69809446189e9a6eac4dfb19235e7764283f43e --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/simple/TweetLikeReverse.java @@ -0,0 +1,36 @@ +package net.oschina.app.improve.bean.simple; + +/** + * 动弹赞和取消赞 + * Created by huanghaibin_dev + * on 2016/7/25. + */ +public class TweetLikeReverse { + private Author author; + private boolean liked; + private int likeCount; + + public Author getAuthor() { + return author; + } + + public void setAuthor(Author author) { + this.author = author; + } + + public boolean isLiked() { + return liked; + } + + public void setLiked(boolean liked) { + this.liked = liked; + } + + public int getLikeCount() { + return likeCount; + } + + public void setLikeCount(int likeCount) { + this.likeCount = likeCount; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/bean/simple/UserRelation.java b/app/src/main/java/net/oschina/app/improve/bean/simple/UserRelation.java new file mode 100644 index 0000000000000000000000000000000000000000..04b86eaa655d9624a5ab298d17baa5207472615e --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/bean/simple/UserRelation.java @@ -0,0 +1,37 @@ +package net.oschina.app.improve.bean.simple; + +import java.io.Serializable; + +/** + * Created by huanghaibin + * on 16-6-16. + */ +public class UserRelation implements Serializable { + private int relation; + private String author; + private long authorId; + + public int getRelation() { + return relation; + } + + public void setRelation(int relation) { + this.relation = relation; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public long getAuthorId() { + return authorId; + } + + public void setAuthorId(long authorId) { + this.authorId = authorId; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/behavior/CommentBar.java b/app/src/main/java/net/oschina/app/improve/behavior/CommentBar.java new file mode 100644 index 0000000000000000000000000000000000000000..c04fcf26d6e1da3dfc3ad5257d3485473f515d44 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/behavior/CommentBar.java @@ -0,0 +1,125 @@ +package net.oschina.app.improve.behavior; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageButton; +import android.widget.LinearLayout; +import android.widget.TextView; + +import net.oschina.app.R; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.account.activity.LoginActivity; +import net.oschina.app.improve.widget.BottomSheetBar; + +/** + * Created by haibin + * on 2016/11/10. + * Change by fei + * on 2016/11/17 + * desc:详情页输入框 + */ +@SuppressWarnings("all") +public class CommentBar { + + private Context mContext; + private View mRootView; + private FrameLayout mFrameLayout; + private ViewGroup mParent; + private ImageButton mFavView; + private ImageButton mShareView; + private TextView mCommentText; + private BottomSheetBar mDelegation; + private LinearLayout mCommentLayout; + + + private CommentBar(Context context) { + this.mContext = context; + } + + public static CommentBar delegation(Context context, ViewGroup parent) { + CommentBar bar = new CommentBar(context); + bar.mRootView = LayoutInflater.from(context).inflate(R.layout.layout_comment_bar, parent, false); + bar.mParent = parent; + bar.mDelegation = BottomSheetBar.delegation(context); + bar.mParent.addView(bar.mRootView); + bar.initView(); + return bar; + } + + private void initView() { + //((CoordinatorLayout.LayoutParams) mRootView.getLayoutParams()).setBehavior(new FloatingAutoHideDownBehavior()); + mFavView = (ImageButton) mRootView.findViewById(R.id.ib_fav); + mShareView = (ImageButton) mRootView.findViewById(R.id.ib_share); + mCommentText = (TextView) mRootView.findViewById(R.id.tv_comment); + mCommentLayout = (LinearLayout) mRootView.findViewById(R.id.ll_comment); + mCommentLayout.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (AccountHelper.isLogin()) { + mDelegation.show(mCommentText.getHint().toString()); + } else { + LoginActivity.show(mContext); + } + } + }); + } + + /** + * share 2 three sdk + * + * @param listener + */ + public void setShareListener(View.OnClickListener listener) { + mShareView.setOnClickListener(listener); + } + + /** + * favorite the detail + * + * @param listener + */ + public void setFavListener(View.OnClickListener listener) { + mFavView.setOnClickListener(listener); + } + + public void setCommentListener(View.OnClickListener listener) { + mCommentText.setOnClickListener(listener); + } + + public void setCommentHint(String text) { + mCommentText.setHint(text); + } + + public void setFavDrawable(int drawable) { + mFavView.setImageResource(drawable); + } + + public BottomSheetBar getBottomSheet() { + return mDelegation; + } + + public void setCommitButtonEnable(boolean enable) { + mDelegation.getBtnCommit().setEnabled(enable); + } + + public void hideShare() { + mShareView.setVisibility(View.GONE); + } + + public void hideFav() { + mFavView.setVisibility(View.GONE); + } + + public TextView getCommentText() { + return mCommentText; + } + + + public void performClick() { + mCommentLayout.performClick(); + } + +} diff --git a/app/src/main/java/net/oschina/app/improve/behavior/FloatingAutoHideDownBehavior.java b/app/src/main/java/net/oschina/app/improve/behavior/FloatingAutoHideDownBehavior.java new file mode 100644 index 0000000000000000000000000000000000000000..82d2e80dc891135af5a5875c5d3da8732194c57e --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/behavior/FloatingAutoHideDownBehavior.java @@ -0,0 +1,167 @@ +package net.oschina.app.improve.behavior; + +import android.content.Context; +import android.support.design.widget.CoordinatorLayout; +import android.support.v4.view.ViewCompat; +import android.support.v4.widget.NestedScrollView; +import android.util.AttributeSet; +import android.view.View; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.Interpolator; + +import net.oschina.app.R; +import net.oschina.app.util.TDevice; + +/** + * 滚动时隐藏的Behavior + * Created by thanatos on 16/2/17. + */ +public class FloatingAutoHideDownBehavior extends CoordinatorLayout.Behavior { + private static final Interpolator INTERPOLATOR = new DecelerateInterpolator(); + private boolean mIsAnimatingOut = false; + private boolean mIsScrollToBottom = false; + + public FloatingAutoHideDownBehavior(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public FloatingAutoHideDownBehavior() { + super(); + } + + @Override + public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) { + super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed); + +// if (!mIsScrollToBottom) { +// float mPreTranslationY = dy + child.getTranslationY(); +// if (mPreTranslationY <= 0) { +// child.setTranslationY(0); +// mIsAnimatingOut = true; +// } +// if (mPreTranslationY >= child.getHeight()) { +// child.setTranslationY(child.getHeight()); +// mIsAnimatingOut = false; +// } +// if (mPreTranslationY > 0 && mPreTranslationY < child.getHeight()) { +// child.setTranslationY(mPreTranslationY); +// mIsAnimatingOut = dy > 0; +// } +// } + } + + @Override + public boolean layoutDependsOn(CoordinatorLayout parent, final View child, View dependency) { + if (child != null && dependency != null && dependency instanceof NestedScrollView) { + NestedScrollView s = (NestedScrollView) dependency; + + if (s.getChildCount() > 0 && child.getHeight() > 0) { + View view = s.getChildAt(s.getChildCount() - 1); + if (view.getTag(R.id.detail_behavior_content_padding_done) == null) { + int paddingBottom = view.getPaddingBottom() + child.getHeight(); + view.setTag(R.id.detail_behavior_content_padding_done, paddingBottom); + view.setPadding(view.getPaddingLeft(), + view.getPaddingTop(), + view.getPaddingRight(), + paddingBottom); + } + } + + s.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() { + @Override + public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) { + if (v.getChildCount() > 0) { + // Grab the last child placed in the ScrollView, we need it to determinate the bottom position. + View view = v.getChildAt(v.getChildCount() - 1); + // Calculate the scrolldiff + int diff = (view.getBottom() - (v.getHeight() + scrollY)); + // if diff is zero, then the bottom has been reached + if (diff == 0) { + // notify that we have reached the bottom + animateIn(child); + mIsScrollToBottom = true; + } else { + mIsScrollToBottom = false; + } + } + } + }); + } + return super.layoutDependsOn(parent, child, dependency); + } + + @Override + public boolean onStartNestedScroll(final CoordinatorLayout coordinatorLayout, final View child, + final View directTargetChild, final View target, final int nestedScrollAxes) { + // 滑动时隐藏软键盘 + TDevice.hideSoftKeyboard(coordinatorLayout); + + // Ensure we react to vertical scrolling + return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL + || super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes); + } + + @Override + public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target) { + super.onStopNestedScroll(coordinatorLayout, child, target); + + if (child.getTranslationY() == 0 || child.getTranslationY() == child.getHeight()) return; + + if (mIsAnimatingOut) { + animateOut(child); + } else { + animateIn(child); + } + + } + + private void animateOut(final View button) { +// button.animate() +// .translationY(button.getHeight()) +// .setInterpolator(INTERPOLATOR) +// .setDuration(200) +// .setListener(new AnimatorListenerAdapter() { +// @Override +// public void onAnimationEnd(Animator animation) { +// button.setTranslationY(button.getHeight()); +// } +// }); + } + + private void animateIn(final View button) { +// button.animate() +// .translationY(0) +// .setInterpolator(INTERPOLATOR) +// .setDuration(200) +// .setListener(new AnimatorListenerAdapter() { +// @Override +// public void onAnimationEnd(Animator animation) { +// button.setTranslationY(0); +// } +// }); + } + + + /** + * 点击内容栏唤起底部操作区域 + * + * @param coordinatorLayout 外部CoordinatorLayout + * @param contentView 滚动区域 + * @param bottomView 滚动时隐藏底部区域 + */ + public static void showBottomLayout(CoordinatorLayout coordinatorLayout, View contentView, final View bottomView) { + //coordinatorLayout.onStartNestedScroll(contentView, null, ViewCompat.SCROLL_AXIS_VERTICAL); + //coordinatorLayout.onNestedPreScroll(bottomView, 0, -1, new int[2]); + //coordinatorLayout.onStopNestedScroll(null); +// bottomView.animate() +// .translationY(0) +// .setInterpolator(INTERPOLATOR) +// .setDuration(200) +// .setListener(new AnimatorListenerAdapter() { +// @Override +// public void onAnimationEnd(Animator animation) { +// bottomView.setTranslationY(0); +// } +// }); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/behavior/KeyboardActionDelegation.java b/app/src/main/java/net/oschina/app/improve/behavior/KeyboardActionDelegation.java new file mode 100644 index 0000000000000000000000000000000000000000..471c8098a6c0c3f939197dcf8bda09c7781cdae0 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/behavior/KeyboardActionDelegation.java @@ -0,0 +1,165 @@ +package net.oschina.app.improve.behavior; + +import android.content.Context; +import android.os.Handler; +import android.text.Spannable; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; +import android.widget.ImageView; + +import net.oschina.app.emoji.Emojicon; +import net.oschina.app.emoji.InputHelper; + +/** + * 键盘, emotion按钮, 输入框, emotion面板之间的相互关系委派给这个类管理 + * Created by thanatos on 3/4/16. + */ +public class KeyboardActionDelegation { + private ImageView mBtnEmotion; + private EditText mInput; + private Context mContext; + private ViewGroup mEmotionPanel; + + private boolean isShowSoftInput; + + // 事件回馈 + private OnActionChangeListener mOnActionChangeListener; + + private KeyboardActionDelegation(Context context, EditText input, ImageView button, ViewGroup view, OnActionChangeListener listener) { + this.mBtnEmotion = button; + this.mInput = input; + this.mContext = context; + this.mEmotionPanel = view; + this.mOnActionChangeListener = listener; + init(); + } + + public static KeyboardActionDelegation delegation(Context context, EditText input, ImageView button, ViewGroup view) { + return new KeyboardActionDelegation(context, input, button, view, null); + } + + + public static KeyboardActionDelegation delegation(Context context, EditText input, ImageView button, ViewGroup view, OnActionChangeListener listener) { + return new KeyboardActionDelegation(context, input, button, view, listener); + } + + /** + * 初始化, 绑定事件 + */ + private void init() { + mInput.setOnFocusChangeListener(new View.OnFocusChangeListener() { + @Override + public void onFocusChange(View v, boolean hasFocus) { + if (hasFocus) { + hideEmotionPanel(); + } else { + hideSoftKeyboard(); + } + } + }); + + mInput.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (!isEmotionPanelShowing()) return; + hideEmotionPanel(); + } + }); + + mBtnEmotion.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (isEmotionPanelShowing()) { + hideEmotionPanel(); + } else { + showEmotionPanel(); + } + } + }); + } + + public void showEmotionPanel() { + mBtnEmotion.setSelected(true); + hideSoftKeyboard(); + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + mEmotionPanel.setVisibility(View.VISIBLE); + + OnActionChangeListener listener = mOnActionChangeListener; + if (listener != null) { + listener.onShowEmotionPanel(KeyboardActionDelegation.this); + } + } + }, 300); + } + + private boolean isEmotionPanelShowing() { + return mEmotionPanel.getVisibility() == View.VISIBLE; + } + + /** + * 隐藏软键盘 + */ + private void hideSoftKeyboard() { + ((InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE)) + .hideSoftInputFromWindow(mInput.getWindowToken(), 0); + isShowSoftInput = false; + } + + /** + * 隐藏表情面板 + */ + private void hideEmotionPanel() { + mEmotionPanel.setVisibility(View.GONE); + mBtnEmotion.setSelected(false); + + OnActionChangeListener listener = mOnActionChangeListener; + if (listener != null) { + listener.onHideEmotionPanel(this); + } + } + + public boolean isShowSoftInput() { + return isShowSoftInput; + } + + public void onEmotionItemSelected(Emojicon emotion) { + if (mInput == null || emotion == null) { + return; + } + int start = mInput.getSelectionStart(); + int end = mInput.getSelectionEnd(); + if (start == end) { + mInput.append(InputHelper.displayEmoji(mContext.getResources(), emotion.getRemote())); + } else { + Spannable str = InputHelper.displayEmoji(mContext.getResources(), emotion.getRemote()); + mInput.getText().replace(Math.min(start, end), Math.max(start, end), str, 0, str.length()); + } + } + + /** + * 当使用回退键时 + * + * @return + */ + public boolean onTurnBack() { + if (isEmotionPanelShowing()) { + hideEmotionPanel(); + return false; + } + if (isShowSoftInput()) { + hideEmotionPanel(); + return false; + } + return true; + } + + public interface OnActionChangeListener { + void onHideEmotionPanel(KeyboardActionDelegation delegation); + + void onShowEmotionPanel(KeyboardActionDelegation delegation); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/behavior/KeyboardInputDelegation.java b/app/src/main/java/net/oschina/app/improve/behavior/KeyboardInputDelegation.java new file mode 100644 index 0000000000000000000000000000000000000000..d5afe6889400767a004501c8235e3b0a9abb84a4 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/behavior/KeyboardInputDelegation.java @@ -0,0 +1,291 @@ +package net.oschina.app.improve.behavior; + +import android.content.Context; +import android.support.design.widget.CoordinatorLayout; +import android.support.v4.app.FragmentManager; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.EditorInfo; +import android.widget.Button; +import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import net.oschina.app.R; +import net.oschina.app.emoji.EmojiKeyboardFragment; +import net.oschina.app.emoji.Emojicon; +import net.oschina.app.emoji.InputHelper; +import net.oschina.app.emoji.OnEmojiClickListener; + +/** + * 底部操作的抽取 + * Created by thanatos on 16/6/21. + */ +public class KeyboardInputDelegation { + + private Context context; + private boolean isLastEmpty = true; + + private CoordinatorLayout mCoorLayout; + private View mScrollerView; + private View mWrapperView; + + private EditText mViewInput; + private ImageView mViewShare; + private ImageView mViewFavor; + private ImageView mViewEmoji; + private ImageView mViewPic; + private FrameLayout mKeyboardFrame; + + private Button mBtnSend; + private LinearLayout mBottomLayout; + + private KeyboardActionDelegation mActionDelegation; + + private int mInputHeight; + private int mCurrentInputHeight; + + private KeyboardInputDelegation(Context context) { + this.context = context; + } + + public static KeyboardInputDelegation delegation(Context context, CoordinatorLayout mCoorLayout, View mScrollerView) { + KeyboardInputDelegation delegator = new KeyboardInputDelegation(context); + View view = LayoutInflater.from(context).inflate(R.layout.view_input_wrap, mCoorLayout, false); + delegator.setWrapperView(view); + delegator.setCoorLayout(mCoorLayout); + delegator.setScrollerView(mScrollerView); + mCoorLayout.addView(view); + return delegator; + } + + public void setBehavior(CoordinatorLayout.Behavior behavior) { + ((CoordinatorLayout.LayoutParams) mWrapperView.getLayoutParams()).setBehavior(behavior); + } + + public void showEmoji(FragmentManager fragManager) { + if (mKeyboardFrame == null) + mKeyboardFrame = (FrameLayout) mWrapperView.findViewById(R.id.emoji_keyboard_fragment); + if (mViewEmoji == null) + mViewEmoji = (ImageView) mWrapperView.findViewById(R.id.iv_emoji); + mViewEmoji.setVisibility(View.VISIBLE); + + final EmojiKeyboardFragment mKeyboardFragment = new EmojiKeyboardFragment(); + mKeyboardFragment.setDelegate(true); + mKeyboardFragment.setOnEmojiClickListener(new OnEmojiClickListener() { + @Override + public void onDeleteButtonClick(View v) { + InputHelper.backspace(mViewInput); + } + + @Override + public void onEmojiClick(Emojicon v) { + mActionDelegation.onEmotionItemSelected(v); + } + }); + mCoorLayout.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + onTurnBack(); + } + return false; + } + }); + + fragManager.beginTransaction() + .replace(R.id.emoji_keyboard_fragment, mKeyboardFragment) + .commit(); + + mActionDelegation = KeyboardActionDelegation.delegation(context, mViewInput, mViewEmoji, mKeyboardFrame, new KeyboardActionDelegation.OnActionChangeListener() { + @Override + public void onHideEmotionPanel(KeyboardActionDelegation delegation) { + mKeyboardFragment.hideEmojiKeyBoard(); + } + + @Override + public void onShowEmotionPanel(KeyboardActionDelegation delegation) { + mKeyboardFragment.showEmojiKeyBoard(); + } + }); + } + + public void hideSendButton() { + if (mBottomLayout == null) { + mBottomLayout = (LinearLayout) mWrapperView.findViewById(R.id.ll_bottom); + + } + mBottomLayout.setVisibility(View.VISIBLE); + mBtnSend.setVisibility(View.GONE); + } + + public void showSendButton() { + if (mBottomLayout == null) { + mBottomLayout = (LinearLayout) mWrapperView.findViewById(R.id.ll_bottom); + } + mBottomLayout.setVisibility(View.GONE); + mBtnSend.setVisibility(View.VISIBLE); + } + + public void showShare(View.OnClickListener l) { + if (mViewShare == null) + mViewShare = (ImageView) mWrapperView.findViewById(R.id.iv_share); + if (l != null) mViewShare.setOnClickListener(l); + mViewShare.setVisibility(View.VISIBLE); + } + + public void showFavor(View.OnClickListener l) { + if (mViewFavor == null) + mViewFavor = (ImageView) mWrapperView.findViewById(R.id.iv_fav); + if (l != null) mViewFavor.setOnClickListener(l); + mViewFavor.setVisibility(View.VISIBLE); + } + + public void setFavorDrawable(int drawable) { + mViewFavor.setImageResource(drawable); + } + + public void showPic(View.OnClickListener l) { + if (mViewPic == null) { + mViewPic = (ImageView) mWrapperView.findViewById(R.id.iv_pic); + } + if (l != null) mViewPic.setOnClickListener(l); + mViewPic.setVisibility(View.VISIBLE); + } + + private void setWrapperView(View view) { + this.mWrapperView = view; + mViewInput = (EditText) this.mWrapperView.findViewById(R.id.et_input); + mViewInput.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { + @Override + public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { + if (mInputHeight == 0) { + mInputHeight = mViewInput.getMeasuredHeight(); + } + } + }); + mBtnSend = (Button) mWrapperView.findViewById(R.id.btn_send); + } + + private void setCoorLayout(CoordinatorLayout view) { + this.mCoorLayout = view; + } + + private void setScrollerView(View view) { + this.mScrollerView = view; + } + + public void setAdapter(final KeyboardInputAdapter mInputAdapter) { + mViewInput.setOnEditorActionListener(new TextView.OnEditorActionListener() { + @Override + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + if (actionId == EditorInfo.IME_ACTION_SEND) { +// InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); +// imm.hideSoftInputFromWindow(v.getWindowToken(), 0); + mInputAdapter.onSubmit(v, v.getText().toString()); + return true; + } + return false; + } + }); + mViewInput.setOnKeyListener(new View.OnKeyListener() { + @Override + public boolean onKey(View v, int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_DEL && event.getAction() == KeyEvent.ACTION_DOWN) { + mInputAdapter.onBackSpace(v); + if (!TextUtils.isEmpty(mViewInput.getText().toString())) { + isLastEmpty = false; + return false; + } + if (TextUtils.isEmpty(mViewInput.getText().toString()) && !isLastEmpty) { + isLastEmpty = true; + return false; + } + mInputAdapter.onFinalBackSpace(v); + return true; + } + return false; + } + }); + + } + + public void setSendListener(View.OnClickListener listener) { + mBtnSend.setOnClickListener(listener); + mViewInput.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + if (!TextUtils.isEmpty(s.toString().replace("\n", "").replace(" ", ""))) { + showSendButton(); + } else { + hideSendButton(); + } + } + + @Override + public void afterTextChanged(Editable s) { + mCurrentInputHeight = mViewInput.getMeasuredHeight(); + } + }); + mViewInput.setOnFocusChangeListener(new View.OnFocusChangeListener() { + @Override + public void onFocusChange(View v, boolean hasFocus) { + if (!hasFocus) { + if (TextUtils.isEmpty(getInputText())) { + mViewInput.setText(""); + } + mViewInput.getLayoutParams().height = mInputHeight; + mViewInput.requestLayout(); + } else { + if (mCurrentInputHeight >= mInputHeight) { + mViewInput.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT; + mViewInput.requestLayout(); + } + } + } + }); + } + + public EditText getInputView() { + return mViewInput; + } + + public String getInputText() { + return mViewInput.getText().toString().trim(); + } + + public void notifyWrapper() { + FloatingAutoHideDownBehavior.showBottomLayout(mCoorLayout, mScrollerView, mWrapperView); + } + + public boolean onTurnBack() { + return mActionDelegation == null || mActionDelegation.onTurnBack(); + } + + public void onBackSpace() { + + } + + public static abstract class KeyboardInputAdapter { + public abstract void onSubmit(TextView v, String content); + + public void onBackSpace(View v) { + } + + public void onFinalBackSpace(View v) { + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/comment/CommentExsActivity.java b/app/src/main/java/net/oschina/app/improve/comment/CommentExsActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..d4a3bb7ff62d412e75f03577f296ad14d9fc63d5 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/comment/CommentExsActivity.java @@ -0,0 +1,438 @@ +package net.oschina.app.improve.comment; + +import android.app.ProgressDialog; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.support.design.widget.CoordinatorLayout; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.text.TextUtils; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.bumptech.glide.RequestManager; +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.AppContext; +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.account.activity.LoginActivity; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.base.activities.BaseBackActivity; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.bean.base.PageBean; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.bean.comment.Comment; +import net.oschina.app.improve.bean.simple.CommentEX; +import net.oschina.app.improve.behavior.CommentBar; +import net.oschina.app.improve.utils.DialogHelper; +import net.oschina.app.improve.widget.RecyclerRefreshLayout; +import net.oschina.app.ui.SelectFriendsActivity; +import net.oschina.app.util.TDevice; +import net.oschina.app.util.UIHelper; +import net.oschina.app.widget.TweetTextView; + +import java.lang.reflect.Type; +import java.util.List; + +import butterknife.Bind; +import cz.msebera.android.httpclient.Header; + +public class CommentExsActivity extends BaseBackActivity { + private long mId; + private int mType; + + private PageBean mPageBean; + + @Bind(R.id.lay_refreshLayout) + RecyclerRefreshLayout mRefreshLayout; + + @Bind(R.id.lay_blog_detail_comment) + RecyclerView mLayComments; + + @Bind(R.id.activity_comments) + CoordinatorLayout mCoorLayout; + + private Adapter mAdapter; + private Comment reply; + private CommentBar mDelegation; + private View.OnClickListener onReplyBtnClickListener; + private ProgressDialog mDialog; + + public static void show(Context context, long id, int type) { + Intent intent = new Intent(context, CommentExsActivity.class); + intent.putExtra("id", id); + intent.putExtra("type", type); + context.startActivity(intent); + } + + @Override + protected int getContentView() { + return R.layout.activity_comments; + } + + @Override + protected boolean initBundle(Bundle bundle) { + mId = bundle.getLong("id"); + mType = bundle.getInt("type"); + return super.initBundle(bundle); + } + + @Override + protected void initWidget() { + super.initWidget(); + LinearLayoutManager manager = new LinearLayoutManager(this); + mLayComments.setLayoutManager(manager); + + mAdapter = new Adapter(this); + mLayComments.setAdapter(mAdapter); + + mDelegation = CommentBar.delegation(this, mCoorLayout); + mDelegation.getBottomSheet().setCommitListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + handleSendComment(mId, reply == null ? 0 : reply.getId(), reply == null ? 0 : reply.getAuthor().getId(), mDelegation.getBottomSheet().getCommentText()); + } + }); + + mDelegation.hideFav(); + mDelegation.hideShare(); + + mDelegation.getBottomSheet().setMentionListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (AccountHelper.isLogin()) + SelectFriendsActivity.show(CommentExsActivity.this); + else + LoginActivity.show(CommentExsActivity.this); + } + }); + + mDelegation.getBottomSheet().getEditText().setOnKeyListener(new View.OnKeyListener() { + @Override + public boolean onKey(View v, int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_DEL && event.getAction() == KeyEvent.ACTION_DOWN) { + if (reply == null) return false; + reply = null; + mDelegation.getCommentText().setHint("发表评论"); + mDelegation.getBottomSheet().getEditText().setHint("发表评论"); + } + return false; + } + }); + mRefreshLayout.setColorSchemeResources( + R.color.swiperefresh_color1, R.color.swiperefresh_color2, + R.color.swiperefresh_color3, R.color.swiperefresh_color4); + } + + @Override + protected void initData() { + super.initData(); + mRefreshLayout.setSuperRefreshLayoutListener(new RecyclerRefreshLayout.SuperRefreshLayoutListener() { + @Override + public void onRefreshing() { + getData(true, null); + } + + @Override + public void onLoadMore() { + String token = null; + if (mPageBean != null) + token = mPageBean.getNextPageToken(); + getData(false, token); + } + }); + + mRefreshLayout.post(new Runnable() { + @Override + public void run() { + mRefreshLayout.setRefreshing(true); + mRefreshLayout.onRefresh(); + } + }); + } + + /** + * 检查当前数据,并检查网络状况 + * + * @return 返回当前登录用户, 未登录或者未通过检查返回0 + */ + private long requestCheck() { + if (mId == 0) { + AppContext.showToast("数据加载中..."); + return 0; + } + if (!TDevice.hasInternet()) { + AppContext.showToastShort(R.string.tip_no_internet); + return 0; + } + if (!AccountHelper.isLogin()) { + UIHelper.showLoginActivity(this); + return 0; + } + // 返回当前登录用户ID + return AccountHelper.getUserId(); + } + + + /** + * handle send comment + */ + private void handleSendComment(long id, final long commentId, long commentAuthorId, String content) { + long uid = requestCheck(); + if (uid == 0) + return; + + if (TextUtils.isEmpty(content)) { + AppContext.showToastShort(R.string.tip_comment_content_empty); + return; + } + OSChinaApi.pubQuestionComment(id, commentId, commentAuthorId, content, new TextHttpResponseHandler() { + @Override + public void onStart() { + super.onStart(); + showWaitDialog(R.string.progress_submit); + } + + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + AppContext.showToast("评论失败!"); + hideWaitDialog(); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + Type type = new TypeToken>() { + }.getType(); + + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, type); + if (resultBean.isSuccess()) { + CommentEX respComment = resultBean.getResult(); + if (respComment != null) { + + Toast.makeText(CommentExsActivity.this, "评论成功", Toast.LENGTH_LONG).show(); + mDelegation.setCommentHint("发表评论"); + mDelegation.getBottomSheet().getEditText().setHint("发表评论"); + getData(true, null); + mDelegation.getBottomSheet().dismiss(); + } + } + hideWaitDialog(); + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + hideWaitDialog(); + } + + @Override + public void onFinish() { + super.onFinish(); + mDelegation.getBottomSheet().dismiss(); + } + }); + + } + + /** + * show waittDialog + * + * @param messageId messageId + * @return progressDialog + */ + private ProgressDialog showWaitDialog(int messageId) { + String message = getResources().getString(messageId); + if (mDialog == null) { + mDialog = DialogHelper.getProgressDialog(this, message); + } + + mDialog.setMessage(message); + mDialog.show(); + + return mDialog; + } + + /** + * hideWaitDialog + */ + public void hideWaitDialog() { + ProgressDialog dialog = mDialog; + if (dialog != null) { + mDialog = null; + try { + dialog.dismiss(); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + } + + private void getData(final boolean clearData, String token) { + OSChinaApi.getComments(mId, mType, "refer", token, new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + + } + + @Override + public void onFinish() { + super.onFinish(); + mRefreshLayout.onComplete(); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + Type type = new TypeToken>>() { + }.getType(); + + ResultBean> resultBean = AppOperator.createGson().fromJson(responseString, type); + if (resultBean != null && resultBean.isSuccess()) { + if (resultBean.getResult() != null + && resultBean.getResult().getItems() != null + && resultBean.getResult().getItems().size() > 0) { + mPageBean = resultBean.getResult(); + handleData(mPageBean.getItems(), clearData); + return; + } + } + mAdapter.setState(BaseRecyclerAdapter.STATE_NO_MORE, true); + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + } + }); + } + + private void handleData(List comments, boolean clearData) { + if (clearData) + mAdapter.clear(); + + mAdapter.setState(BaseRecyclerAdapter.STATE_LOADING, false); + mAdapter.addAll(comments); + if (mAdapter.getItems().size() < 20) + mAdapter.setState(BaseRecyclerAdapter.STATE_NO_MORE, true); + } + + public View.OnClickListener getReplyBtnClickListener() { + if (onReplyBtnClickListener == null) { + onReplyBtnClickListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + Comment comment = (Comment) v.getTag(); + mDelegation.setCommentHint("@" + comment.getAuthor() + " :"); + mDelegation.getBottomSheet().getEditText().setHint("@" + comment.getAuthor() + " :"); + reply = comment; + } + }; + } + return onReplyBtnClickListener; + } + + private static class CommentHolder extends RecyclerView.ViewHolder { + private ImageView mAvatar; + private TextView mName; + private TextView mDate; + private TweetTextView mContent; + private LinearLayout mRefers; + private ImageView btn_comment, iv_best_comment; + + CommentHolder(View itemView) { + super(itemView); + + mAvatar = (ImageView) itemView.findViewById(R.id.iv_avatar); + mName = (TextView) itemView.findViewById(R.id.tv_name); + mDate = (TextView) itemView.findViewById(R.id.tv_pub_date); + btn_comment = (ImageView) itemView.findViewById(R.id.btn_comment); + iv_best_comment = (ImageView) itemView.findViewById(R.id.iv_best_answer); + mContent = ((TweetTextView) itemView.findViewById(R.id.tv_content)); + mRefers = ((LinearLayout) itemView.findViewById(R.id.lay_refer)); + } + + void setData(Comment comment, RequestManager imageLoader, View.OnClickListener l) { + if (comment.getAuthor().getPortrait() != null) + imageLoader.load(comment.getAuthor().getPortrait()).error(R.mipmap.widget_dface) + .into((mAvatar)); + else + mAvatar.setImageResource(R.mipmap.widget_dface); + + mName.setText(comment.getAuthor().getName()); + mDate.setText(comment.getPubDate()); + CommentsUtil.formatHtml(mContent.getResources(), mContent, comment.getContent()); + + mRefers.removeAllViews(); + if (comment.getRefer() != null) { + // 最多5层 + View view = CommentsUtil.getReplyLayout(LayoutInflater.from(mRefers.getContext()), comment.getReply(), 0); + mRefers.addView(view); + } + + btn_comment.setTag(comment); + if (l != null) + btn_comment.setOnClickListener(l); + } + } + + private class Adapter extends BaseRecyclerAdapter { + + Adapter(Context context) { + super(context, ONLY_FOOTER); + mState = STATE_LOADING; + setOnItemClickListener(new OnItemClickListener() { + @Override + public void onItemClick(int position, long itemId) { + CommentExsActivity.this.onItemClick(getItem(position)); + } + }); + } + + @Override + protected RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type) { + LayoutInflater inflater = LayoutInflater.from(parent.getContext()); + View view = inflater.inflate(R.layout.lay_comment_item_ex, parent, false); + return new CommentHolder(view); + } + + @Override + protected void onBindDefaultViewHolder(RecyclerView.ViewHolder holder, Comment item, int position) { + if (holder instanceof CommentHolder) { + CommentHolder commentHolder = (CommentHolder) holder; + RequestManager requestManager = getImageLoader(); + if (requestManager != null) + commentHolder.setData(item, requestManager, null); + if (item.isBest()) { + commentHolder.btn_comment.setVisibility(View.GONE); + commentHolder.iv_best_comment.setVisibility(View.VISIBLE); + } else { + commentHolder.btn_comment.setVisibility(View.VISIBLE); + commentHolder.iv_best_comment.setVisibility(View.GONE); + } + } + } + + } + + private void onItemClick(Comment comment) { + QuesAnswerDetailActivity.show(this, comment, mId, mType); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode == RESULT_OK && data != null) { + mDelegation.getBottomSheet().handleSelectFriendsResult(data); + mDelegation.setCommentHint(mDelegation.getBottomSheet().getEditText().getHint().toString()); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/comment/CommentReferView.java b/app/src/main/java/net/oschina/app/improve/comment/CommentReferView.java new file mode 100644 index 0000000000000000000000000000000000000000..27c24e2591cdd26f548f62f2f2fe9a60ea7ff554 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/comment/CommentReferView.java @@ -0,0 +1,53 @@ +package net.oschina.app.improve.comment; + +import android.content.Context; +import android.support.annotation.Nullable; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.LinearLayout; + +import net.oschina.app.improve.bean.comment.Comment; +import net.oschina.app.improve.bean.comment.Refer; + +/** + * Created by fei + * on 2016/11/21. + * desc: + */ + +public class CommentReferView extends LinearLayout { + + public CommentReferView(Context context) { + super(context); + initView(); + } + + public CommentReferView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + initView(); + } + + public CommentReferView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initView(); + } + + private void initView() { + setOrientation(VERTICAL); + } + + + public void addComment(final Comment comment) { + removeAllViews();//因为在list中有复用问题,不同的refers长度不同,并且不一样,所以需要先清除掉原先的布局,包括 + Refer[] refers = comment.getRefer(); + + if (refers != null && refers.length > 0) { + LayoutInflater inflater = LayoutInflater.from(getContext()); + View child = CommentsUtil.getReferLayout(inflater, refers, 0); + addView(child, indexOfChild(child)); + } + + + } +} diff --git a/app/src/main/java/net/oschina/app/improve/comment/CommentView.java b/app/src/main/java/net/oschina/app/improve/comment/CommentView.java new file mode 100644 index 0000000000000000000000000000000000000000..c28b5928c6668b99dcfa6d59b00797a0e8bccb75 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/comment/CommentView.java @@ -0,0 +1,415 @@ +package net.oschina.app.improve.comment; + +import android.annotation.SuppressLint; +import android.app.ProgressDialog; +import android.content.Context; +import android.support.annotation.Nullable; +import android.support.annotation.StringRes; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.bumptech.glide.RequestManager; +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.AppContext; +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.account.activity.LoginActivity; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.bean.base.PageBean; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.bean.comment.Comment; +import net.oschina.app.improve.bean.comment.Refer; +import net.oschina.app.improve.bean.comment.Vote; +import net.oschina.app.improve.behavior.CommentBar; +import net.oschina.app.improve.user.activities.OtherUserHomeActivity; +import net.oschina.app.improve.utils.DialogHelper; +import net.oschina.app.util.StringUtils; +import net.oschina.app.util.TDevice; +import net.oschina.app.widget.TweetTextView; +import net.oschina.common.utils.CollectionUtil; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; + +import cz.msebera.android.httpclient.Header; + +/** + * Created by fei + * on 2016/11/16. + * desc: 资讯、问答、博客、翻译、活动详情评论列表当中进行展示的子view. + * 包括直接渲染出评论下的refer和reply + */ +public class CommentView extends LinearLayout implements View.OnClickListener { + + private long mId; + private int mType; + private TextView mTitle; + private TextView mSeeMore; + private LinearLayout mLayComments; + private ProgressDialog mDialog; + private View mLabelLine; + private View mLabelBottomLine; + private CommentBar commentBar; + + public CommentView(Context context) { + super(context); + init(); + } + + public CommentView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + init(); + } + + public CommentView(Context context, @Nullable AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + private void init() { + setOrientation(VERTICAL); + LayoutInflater inflater = LayoutInflater.from(getContext()); + inflater.inflate(R.layout.lay_detail_comment_layout, this, true); + mTitle = (TextView) findViewById(R.id.tv_blog_detail_comment); + mLabelLine = findViewById(R.id.label_line); + mLayComments = (LinearLayout) findViewById(R.id.lay_detail_comment); + mLabelBottomLine = findViewById(R.id.label_line_bottom); + mSeeMore = (TextView) findViewById(R.id.tv_see_more_comment); + } + + public void setTitle(String title) { + if (!TextUtils.isEmpty(title)) { + mTitle.setText(title); + } + } + + public void setCommentBar(CommentBar commentBar) { + this.commentBar = commentBar; + } + + /** + * @return TypeToken + */ + Type getCommentType() { + return new TypeToken>>() { + }.getType(); + } + + /** + * @return TypeToken + */ + Type getVoteType() { + return new TypeToken>() { + }.getType(); + } + + public void init(long id, final int type, int order, final int commentCount, final RequestManager imageLoader, + final OnCommentClickListener onCommentClickListener) { + this.mId = id; + this.mType = type; + + mSeeMore.setVisibility(View.GONE); + setVisibility(GONE); + + OSChinaApi.getComments(id, type, "refer,reply", order, null, new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + if (throwable != null) + throwable.printStackTrace(); + } + + @SuppressLint("DefaultLocale") + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + + ResultBean> resultBean = AppOperator.createGson().fromJson(responseString, getCommentType()); + if (resultBean.isSuccess()) { + List comments = resultBean.getResult().getItems(); + int size = comments.size(); + if (type == OSChinaApi.COMMENT_NEWS) { + List hotComments = new ArrayList<>(); + //筛选出热门评论 + for (int i = 0, len = comments.size(); i < (len > 5 ? 5 : len); i++) { + Comment comment = comments.get(i); + if (comment.getVote() > 0) { + hotComments.add(comment); + } + } + comments = hotComments; + int len = comments.size(); + if (len > 0) { + //表示热门评论数目 + setTitle(String.format("%s", getResources().getString(R.string.hot_comment_hint))); + mSeeMore.setVisibility(VISIBLE); + mSeeMore.setOnClickListener(CommentView.this); + } + } else if (commentCount > size) { + mSeeMore.setVisibility(VISIBLE); + mSeeMore.setOnClickListener(CommentView.this); + } + + Comment[] array = CollectionUtil.toArray(comments, Comment.class); + initComment(array, imageLoader, onCommentClickListener); + } + + } catch (Exception e) { + onFailure(statusCode, headers, responseString, e); + } + } + }); + } + + private void initComment(final Comment[] comments, final RequestManager imageLoader, final OnCommentClickListener onCommentClickListener) { + if (mLayComments != null) + if (comments != null && comments.length > 0) { + if (getVisibility() != VISIBLE) { + setVisibility(VISIBLE); + } + + for (int i = 0, len = comments.length; i < len; i++) { + final Comment comment = comments[i]; + if (comment != null) { + final ViewGroup lay = insertComment((i + 1), true, comment, imageLoader, onCommentClickListener); + lay.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (mType == OSChinaApi.COMMENT_EVENT || mType == OSChinaApi.COMMENT_QUESTION) { + QuesAnswerDetailActivity.show(lay.getContext(), comment, mId, mType); + } + } + }); + mLayComments.addView(lay, indexOfChild(mLabelBottomLine)); + if (i == len - 1) { + lay.findViewById(R.id.line).setVisibility(GONE); + } else { + lay.findViewById(R.id.line).setVisibility(View.VISIBLE); + } + } + } + } else { + setVisibility(View.GONE); + } + } + + + @SuppressLint("DefaultLocale") + private ViewGroup insertComment(int position, final boolean first, final Comment comment, final RequestManager imageLoader, final OnCommentClickListener onCommentClickListener) { + final LayoutInflater inflater = LayoutInflater.from(getContext()); + @SuppressLint("InflateParams") final ViewGroup lay = (ViewGroup) inflater.inflate(R.layout.lay_comment_item, null, false); + + ImageView ivAvatar = (ImageView) lay.findViewById(R.id.iv_avatar); + imageLoader.load(comment.getAuthor().getPortrait()).error(R.mipmap.widget_dface) + .into(ivAvatar); + ivAvatar.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + OtherUserHomeActivity.show(getContext(), comment.getAuthor().getId()); + } + }); + final TextView tvVoteCount = (TextView) lay.findViewById(R.id.tv_vote_count); + tvVoteCount.setText(String.valueOf(comment.getVote())); + final ImageView ivVoteStatus = (ImageView) lay.findViewById(R.id.btn_vote); + + final ImageView ivComment = (ImageView) lay.findViewById(R.id.btn_comment); + ivComment.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + commentBar.getBottomSheet().show(String.format("%s %s", + ivComment.getResources().getString(R.string.reply_hint), comment.getAuthor().getName())); + } + }); + + if (mType == OSChinaApi.COMMENT_QUESTION || mType == OSChinaApi.COMMENT_EVENT + || mType == OSChinaApi.COMMENT_TRANSLATION || mType == OSChinaApi.COMMENT_BLOG) { + + tvVoteCount.setVisibility(View.GONE); + ivVoteStatus.setVisibility(View.GONE); + if (comment.isBest()) { + ivComment.setEnabled(false); + ivComment.setImageResource(R.mipmap.label_best_answer); + } else { + ivComment.setEnabled(true); + ivComment.setImageResource(R.mipmap.ic_comment_30); + } + } else { + ivComment.setEnabled(true); + tvVoteCount.setText(String.valueOf(comment.getVote())); + tvVoteCount.setVisibility(View.VISIBLE); + ivVoteStatus.setVisibility(View.VISIBLE); + + if (comment.getVoteState() == 1) { + ivVoteStatus.setImageResource(R.mipmap.ic_thumbup_actived); + ivVoteStatus.setTag(true); + } else if (comment.getVoteState() == 0) { + ivVoteStatus.setImageResource(R.mipmap.ic_thumb_normal); + ivVoteStatus.setTag(null); + } + + ivVoteStatus.setOnClickListener(new OnClickListener() { + @Override + public void onClick(final View v) { + handVote(); + } + + private void handVote() { + + if (!AccountHelper.isLogin()) { + LoginActivity.show(getContext()); + return; + } + if (!TDevice.hasInternet()) { + AppContext.showToast(getResources().getString(R.string.state_network_error), Toast.LENGTH_SHORT); + return; + } + OSChinaApi.voteComment(mType, comment.getId(), comment.getAuthor().getId(), ivVoteStatus.getTag() != null ? 0 : 1, new TextHttpResponseHandler() { + + @Override + public void onStart() { + super.onStart(); + showWaitDialog(R.string.progress_submit); + } + + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + requestFailureHint(throwable); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, getVoteType()); + if (resultBean.isSuccess()) { + Vote vote = resultBean.getResult(); + if (vote != null) { + if (vote.getVoteState() == 1) { + comment.setVoteState(1); + ivVoteStatus.setTag(true); + ivVoteStatus.setImageResource(R.mipmap.ic_thumbup_actived); + } else if (vote.getVoteState() == 0) { + comment.setVoteState(0); + ivVoteStatus.setTag(null); + ivVoteStatus.setImageResource(R.mipmap.ic_thumb_normal); + } + long voteVoteCount = vote.getVote(); + comment.setVote(voteVoteCount); + tvVoteCount.setText(String.valueOf(voteVoteCount)); + } + } else { + AppContext.showToast(resultBean.getMessage(), Toast.LENGTH_SHORT); + } + } + + @Override + public void onFinish() { + super.onFinish(); + hideWaitDialog(); + } + }); + } + }); + } + + String name = comment.getAuthor().getName(); + if (TextUtils.isEmpty(name)) { + name = getResources().getString(R.string.martian_hint); + } + ((TextView) lay.findViewById(R.id.tv_name)).setText(name); + + ((TextView) lay.findViewById(R.id.tv_pub_date)).setText( + String.format("%d%s %s", position, getResources().getString(R.string.floor_hint), + StringUtils.formatSomeAgo(comment.getPubDate()))); + + TweetTextView content = ((TweetTextView) lay.findViewById(R.id.tv_content)); + CommentsUtil.formatHtml(getResources(), content, comment.getContent()); + Refer[] refers = comment.getRefer(); + + if (refers != null && refers.length > 0) { + View view = CommentsUtil.getReferLayout(inflater, refers, 0); + + lay.addView(view, lay.indexOfChild(content)); + } + + lay.findViewById(R.id.btn_comment).setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + onCommentClickListener.onClick(v, comment); + } + }); + + if (!first) { + addView(lay, 0); + } + + return lay; + } + + @Override + public void onClick(View v) { + if (mId != 0 && mType != 0) + CommentsActivity.show(getContext(), mId, mType, OSChinaApi.COMMENT_NEW_ORDER); + } + + /** + * show WaitDialog + * + * @return progressDialog + */ + private ProgressDialog showWaitDialog(@StringRes int messageId) { + + if (mDialog == null) { + if (messageId <= 0) { + mDialog = DialogHelper.getProgressDialog(getContext(), true); + } else { + String message = getResources().getString(messageId); + mDialog = DialogHelper.getProgressDialog(getContext(), message, true); + } + } + mDialog.show(); + + return mDialog; + } + + + /** + * hide waitDialog + */ + private void hideWaitDialog() { + ProgressDialog dialog = mDialog; + if (dialog != null) { + mDialog = null; + try { + dialog.cancel(); + // dialog.dismiss(); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + } + + /** + * request network error + * + * @param throwable throwable + */ + protected void requestFailureHint(Throwable throwable) { + AppContext.showToast(R.string.request_error_hint); + if (throwable != null) { + throwable.printStackTrace(); + } + } +} + + + diff --git a/app/src/main/java/net/oschina/app/improve/comment/CommentsActivity.java b/app/src/main/java/net/oschina/app/improve/comment/CommentsActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..38dab39a1434e5bcd9ea55951fea6ddebf3ba754 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/comment/CommentsActivity.java @@ -0,0 +1,482 @@ +package net.oschina.app.improve.comment; + +import android.annotation.SuppressLint; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.support.design.widget.CoordinatorLayout; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.text.TextUtils; +import android.view.KeyEvent; +import android.view.View; +import android.widget.TextView; +import android.widget.Toast; + +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.AppContext; +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.account.activity.LoginActivity; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.base.activities.BaseBackActivity; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.bean.base.PageBean; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.bean.comment.Comment; +import net.oschina.app.improve.bean.simple.About; +import net.oschina.app.improve.behavior.CommentBar; +import net.oschina.app.improve.comment.adapter.CommentAdapter; +import net.oschina.app.improve.tweet.service.TweetPublishService; +import net.oschina.app.improve.utils.DialogHelper; +import net.oschina.app.improve.widget.RecyclerRefreshLayout; +import net.oschina.app.ui.SelectFriendsActivity; +import net.oschina.app.util.HTMLUtil; +import net.oschina.app.util.TDevice; +import net.oschina.app.util.UIHelper; + +import java.lang.reflect.Type; +import java.util.List; + +import butterknife.Bind; +import cz.msebera.android.httpclient.Header; + +import static net.oschina.app.R.id.tv_back_label; + +/** + * Created by fei + * on 16/11/17 + * desc:详情评论列表ui + */ +public class CommentsActivity extends BaseBackActivity implements BaseRecyclerAdapter.OnItemLongClickListener { + + private long mId; + private int mType; + + private PageBean mPageBean; + + @Bind(R.id.lay_refreshLayout) + RecyclerRefreshLayout mRefreshLayout; + + @Bind(R.id.lay_blog_detail_comment) + RecyclerView mLayComments; + + @Bind(R.id.activity_comments) + CoordinatorLayout mCoordLayout; + @Bind(tv_back_label) + TextView mBack_label; + @Bind(R.id.tv_title) + TextView mTitle; + + private CommentAdapter mCommentAdapter; + private Comment reply; + private CommentBar mDelegation; + private ProgressDialog mDialog; + private boolean mInputDoubleEmpty; + private TextHttpResponseHandler mHandler = new TextHttpResponseHandler() { + @Override + public void onStart() { + super.onStart(); + showWaitDialog(R.string.progress_submit); + } + + @Override + public void onFinish() { + super.onFinish(); + hideWaitDialog(); + } + + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + AppContext.showToast(getResources().getString(R.string.pub_comment_failed)); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + Type type = new TypeToken>() { + }.getType(); + + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, type); + if (resultBean.isSuccess()) { + Comment respComment = resultBean.getResult(); + if (respComment != null) { + handleSyncTweet(); + mDelegation.setCommentHint(getString(mSourceId)); + mDelegation.getBottomSheet().getEditText().setHint(getString(mSourceId)); + Toast.makeText(CommentsActivity.this, getString(R.string.pub_comment_success), Toast.LENGTH_SHORT).show(); + mDelegation.getCommentText().setHint(getString(mSourceId)); + mDelegation.getBottomSheet().getEditText().setText(""); + mDelegation.getBottomSheet().dismiss(); + getData(true, null); + } + } else { + AppContext.showToastShort(resultBean.getMessage()); + } + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + } + }; + + + private int mOrder; + private int mSourceId; + + public static void show(Context context, long id, int type, int order) { + Intent intent = new Intent(context, CommentsActivity.class); + intent.putExtra("id", id); + intent.putExtra("type", type); + intent.putExtra("order", order); + context.startActivity(intent); + } + + @Override + protected int getContentView() { + return R.layout.activity_comments; + } + + @Override + protected boolean initBundle(Bundle bundle) { + mId = bundle.getLong("id"); + mType = bundle.getInt("type"); + mOrder = bundle.getInt("order"); + return super.initBundle(bundle); + } + + @Override + protected void initWidget() { + super.initWidget(); + + mBack_label.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + + mDelegation = CommentBar.delegation(this, mCoordLayout); + mSourceId = R.string.pub_comment_hint; + if (mType == OSChinaApi.COMMENT_QUESTION) { + mSourceId = R.string.answer_hint; + } + if (mType == OSChinaApi.COMMENT_EVENT) { + mSourceId = R.string.comment_hint; + } + mDelegation.getBottomSheet().getEditText().setHint(mSourceId); + mDelegation.hideFav(); + mDelegation.hideShare(); + + mDelegation.getBottomSheet().setMentionListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (AccountHelper.isLogin()) + SelectFriendsActivity.show(CommentsActivity.this); + else + LoginActivity.show(CommentsActivity.this); + } + }); + + mDelegation.getBottomSheet().getEditText().setOnKeyListener(new View.OnKeyListener() { + @Override + public boolean onKey(View v, int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_DEL && event.getAction() == KeyEvent.ACTION_DOWN) { + if (reply == null) return false; + reply = null; + handleKeyDel(); + } + return false; + } + }); + + mDelegation.getBottomSheet().setCommitListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Comment comment = (Comment) v.getTag(); + if (comment == null) { + //当不引用回复的人时候,默认为commentId,authorId为0 + handleSendComment(mType, mId, 0, 0, mDelegation.getBottomSheet().getCommentText()); + } else { + handleSendComment(mType, mId, comment.getId(), comment.getAuthor().getId(), mDelegation.getBottomSheet().getCommentText()); + } + } + }); + + mRefreshLayout.setColorSchemeResources( + R.color.swiperefresh_color1, R.color.swiperefresh_color2, + R.color.swiperefresh_color3, R.color.swiperefresh_color4); + LinearLayoutManager manager = new LinearLayoutManager(this); + mLayComments.setLayoutManager(manager); + + mCommentAdapter = new CommentAdapter(this, getImageLoader(), BaseRecyclerAdapter.ONLY_FOOTER); + mCommentAdapter.setSourceId(mId); + mCommentAdapter.setCommentType(mType); + mCommentAdapter.setDelegation(mDelegation); + mCommentAdapter.setOnItemLongClickListener(this); + mCommentAdapter.setOnItemClickListener(new BaseRecyclerAdapter.OnItemClickListener() { + @Override + public void onItemClick(int position, long itemId) { + + Comment comment = mCommentAdapter.getItem(position); + + if (mType == OSChinaApi.COMMENT_EVENT || mType == OSChinaApi.COMMENT_QUESTION) { + QuesAnswerDetailActivity.show(CommentsActivity.this, comment, mId, mType); + } + } + }); + mLayComments.setAdapter(mCommentAdapter); + } + + @Override + protected void initData() { + super.initData(); + + + mRefreshLayout.setSuperRefreshLayoutListener(new RecyclerRefreshLayout.SuperRefreshLayoutListener() { + @Override + public void onRefreshing() { + getData(true, null); + } + + @Override + public void onLoadMore() { + String token = null; + if (mPageBean != null) + token = mPageBean.getNextPageToken(); + getData(false, token); + } + }); + + mRefreshLayout.post(new Runnable() { + @Override + public void run() { + //第一次请求初始化数据 + getData(true, null); + + } + }); + + } + + Type getCommentType() { + return new TypeToken>>() { + }.getType(); + } + + /** + * 检查当前数据,并检查网络状况 + * + * @return 返回当前登录用户, 未登录或者未通过检查返回0 + */ + private long requestCheck() { + if (mId == 0) { + AppContext.showToast(getResources().getString(R.string.state_loading_error)); + return 0; + } + if (!TDevice.hasInternet()) { + AppContext.showToastShort(R.string.tip_no_internet); + return 0; + } + if (!AccountHelper.isLogin()) { + UIHelper.showLoginActivity(this); + return 0; + } + // 返回当前登录用户ID + return AccountHelper.getUserId(); + } + + + /** + * sync the tweet + */ + private void handleSyncTweet() { + if (mDelegation.getBottomSheet().isSyncToTweet()) { + TweetPublishService.startActionPublish(CommentsActivity.this, + mDelegation.getBottomSheet().getCommentText(), null, + About.buildShare(mId, mType)); + } + } + + /** + * handle send comment + */ + private void handleSendComment(int type, long id, final long commentId, long commentAuthorId, String content) { + long uid = requestCheck(); + if (uid == 0) + return; + + if (TextUtils.isEmpty(content)) { + AppContext.showToastShort(R.string.tip_comment_content_empty); + return; + } + + switch (type) { + case OSChinaApi.COMMENT_QUESTION: + OSChinaApi.pubQuestionComment(id, commentId, commentAuthorId, content, mHandler); + break; + case OSChinaApi.COMMENT_BLOG: + OSChinaApi.pubBlogComment(id, commentId, commentAuthorId, content, mHandler); + break; + case OSChinaApi.COMMENT_TRANSLATION: + OSChinaApi.pubTranslateComment(id, commentId, commentAuthorId, content, mHandler); + break; + case OSChinaApi.COMMENT_EVENT: + OSChinaApi.pubEventComment(id, commentId, commentAuthorId, content, mHandler); + break; + case OSChinaApi.COMMENT_NEWS: + OSChinaApi.pubNewsComment(id, commentId, commentAuthorId, content, mHandler); + break; + default: + break; + } + + } + + + /** + * handle key del content + */ + private void handleKeyDel() { + if (reply.getId() != mId) { + if (TextUtils.isEmpty(mDelegation.getBottomSheet().getCommentText())) { + if (mInputDoubleEmpty) { + mDelegation.setCommentHint(getString(R.string.pub_comment_hint)); + mDelegation.getBottomSheet().getEditText().setHint(getString(R.string.pub_comment_hint)); + } else { + mInputDoubleEmpty = true; + } + } else { + mInputDoubleEmpty = false; + } + } + } + + /** + * show waittDialog + * + * @param messageId messageId + * @return progressDialog + */ + private ProgressDialog showWaitDialog(int messageId) { + String message = getResources().getString(messageId); + if (mDialog == null) { + mDialog = DialogHelper.getProgressDialog(this, message); + } + + mDialog.setMessage(message); + mDialog.show(); + + return mDialog; + } + + /** + * hideWaitDialog + */ + public void hideWaitDialog() { + ProgressDialog dialog = mDialog; + if (dialog != null) { + mDialog = null; + try { + dialog.dismiss(); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + } + + + private void getData(final boolean clearData, String token) { + OSChinaApi.getComments(mId, mType, "refer,reply", mOrder, token, new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + mCommentAdapter.setState(BaseRecyclerAdapter.STATE_LOAD_ERROR, true); + } + + @Override + public void onFinish() { + super.onFinish(); + mRefreshLayout.onComplete(); + } + + @SuppressLint("DefaultLocale") + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + + ResultBean> resultBean = AppOperator.createGson().fromJson(responseString, getCommentType()); + + if (resultBean.isSuccess()) { + mPageBean = resultBean.getResult(); + int titleHintId = R.string.comment_title_hint; + if (mType == OSChinaApi.COMMENT_EVENT || mType == OSChinaApi.COMMENT_QUESTION) { + titleHintId = R.string.answer_hint; + } + mTitle.setText(String.format("%d%s%s", mPageBean.getTotalResults(), getString(R.string.item_hint), getString(titleHintId))); + handleData(mPageBean.getItems(), clearData); + } + + mCommentAdapter.setState( + mPageBean == null || mPageBean.getItems() == null || mPageBean.getItems().size() < 20 ? + BaseRecyclerAdapter.STATE_NO_MORE : BaseRecyclerAdapter.STATE_LOAD_MORE, true); + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + } + }); + } + + private void handleData(List comments, boolean clearData) { + if (clearData) + mCommentAdapter.clear(); + mCommentAdapter.addAll(comments); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode == RESULT_OK && data != null) { + mDelegation.getBottomSheet().handleSelectFriendsResult(data); + mDelegation.setCommentHint(mDelegation.getBottomSheet().getEditText().getHint().toString()); + } + } + + + @Override + public void onLongClick(int position, long itemId) { + + final Comment comment = mCommentAdapter.getItem(position); + if (comment == null) return; + + String[] items; + // if (AccountHelper.getUserId() == (int) comment.getAuthor().getId()) { + // items = new String[]{getString(R.string.copy), getString(R.string.delete)}; + //} else { + items = new String[]{getString(R.string.copy)}; + // } + + DialogHelper.getSelectDialog(this, items, getString(R.string.cancle), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + + switch (i) { + case 0: + TDevice.copyTextToBoard(HTMLUtil.delHTMLTag(comment.getContent())); + break; + case 1: + // TODO: 2016/11/30 delete comment + break; + default: + break; + } + } + }).show(); + + } +} diff --git a/app/src/main/java/net/oschina/app/improve/comment/CommentsUtil.java b/app/src/main/java/net/oschina/app/improve/comment/CommentsUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..585324bbbd7c374866178afde205467c9cb46f43 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/comment/CommentsUtil.java @@ -0,0 +1,98 @@ +package net.oschina.app.improve.comment; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.RectF; +import android.graphics.drawable.ShapeDrawable; +import android.text.Html; +import android.text.Spanned; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import net.oschina.app.R; +import net.oschina.app.emoji.InputHelper; +import net.oschina.app.improve.bean.comment.Refer; +import net.oschina.app.improve.bean.comment.Reply; +import net.oschina.app.widget.MyLinkMovementMethod; +import net.oschina.app.widget.MyURLSpan; +import net.oschina.app.widget.TweetTextView; +import net.qiujuer.genius.ui.Ui; +import net.qiujuer.genius.ui.drawable.shape.BorderShape; + +/** + * Created by JuQiu + * on 16/6/21. + */ + +public final class CommentsUtil { + + @SuppressWarnings("deprecation") + static View getReferLayout(LayoutInflater inflater, Refer[] refer, int count) { + Context context = inflater.getContext(); + @SuppressLint("InflateParams") + ViewGroup lay = (ViewGroup) inflater.inflate(R.layout.lay_comment_item_refer, null, false); + ShapeDrawable drawable = new ShapeDrawable(new BorderShape(new RectF(Ui.dipToPx(context.getResources(), 1), 0, 0, 0))); + drawable.getPaint().setColor(0xffd7d6da); + lay.findViewById(R.id.lay_blog_detail_comment_refer).setBackgroundDrawable(drawable); + + TextView textView = ((TextView) lay.findViewById(R.id.tv_blog_detail_comment_refer)); + drawable = new ShapeDrawable(new BorderShape(new RectF(0, 0, 0, 1))); + drawable.getPaint().setColor(0xffd7d6da); + textView.setBackgroundDrawable(drawable); + formatHtml(context.getResources(), textView, refer[refer.length - 1 - count].getAuthor() + ":
    " + refer[refer.length - 1 - count].getContent()); + if (count < (refer.length < 5 ? refer.length - 1 : 4)) { + count++; + View view = getReferLayout(inflater, refer, count); + lay.addView(view, lay.indexOfChild(textView)); + } + + return lay; + } + + @SuppressWarnings("deprecation") + static View getReplyLayout(LayoutInflater inflater, Reply[] replies, int count) { + Context context = inflater.getContext(); + @SuppressLint("InflateParams") + ViewGroup lay = (ViewGroup) inflater.inflate(R.layout.lay_comment_item_refer, null, false); + ShapeDrawable drawable = new ShapeDrawable(new BorderShape(new RectF(Ui.dipToPx(context.getResources(), 1), 0, 0, 0))); + drawable.getPaint().setColor(0xffd7d6da); + lay.findViewById(R.id.lay_blog_detail_comment_refer).setBackgroundDrawable(drawable); + + TextView textView = ((TextView) lay.findViewById(R.id.tv_blog_detail_comment_refer)); + drawable = new ShapeDrawable(new BorderShape(new RectF(0, 0, 0, 1))); + drawable.getPaint().setColor(0xffd7d6da); + textView.setBackgroundDrawable(drawable); + + formatHtml(context.getResources(), textView, replies[replies.length - 1 - count].getAuthor().getName() + ":
    " + replies[replies.length - 1 - count].getContent()); + + if (count < (replies.length < 5 ? replies.length - 1 : 4)) { + count++; + View view = getReplyLayout(inflater, replies, count); + lay.addView(view, lay.indexOfChild(textView)); + } + + return lay; + } + + @SuppressWarnings("deprecation") + public static void formatHtml(Resources resources, TextView textView, String str) { + str = str.trim(); + + textView.setMovementMethod(MyLinkMovementMethod.a()); + textView.setFocusable(false); + textView.setLongClickable(false); + + if (textView instanceof TweetTextView) { + ((TweetTextView) textView).setDispatchToParent(true); + } + + str = TweetTextView.modifyPath(str); + Spanned span = Html.fromHtml(str); + span = InputHelper.displayEmoji(resources, span.toString()); + textView.setText(span); + MyURLSpan.parseLinkText(textView, span); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/comment/OnCommentClickListener.java b/app/src/main/java/net/oschina/app/improve/comment/OnCommentClickListener.java new file mode 100644 index 0000000000000000000000000000000000000000..a46a473ad910779db5b3322a5c351f97fb0a4eca --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/comment/OnCommentClickListener.java @@ -0,0 +1,14 @@ +package net.oschina.app.improve.comment; + +import android.view.View; + +import net.oschina.app.improve.bean.comment.Comment; + +/** + * Created by JuQiu + * on 16/6/21. + */ + +public interface OnCommentClickListener { + void onClick(View view, Comment comment); +} diff --git a/app/src/main/java/net/oschina/app/improve/comment/QuesAnswerDetailActivity.java b/app/src/main/java/net/oschina/app/improve/comment/QuesAnswerDetailActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..f5b3ec24aba250e73cdb816a462b18e0421adb31 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/comment/QuesAnswerDetailActivity.java @@ -0,0 +1,515 @@ +package net.oschina.app.improve.comment; + +import android.annotation.SuppressLint; +import android.app.Dialog; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.support.design.widget.CoordinatorLayout; +import android.support.v4.widget.NestedScrollView; +import android.support.v7.app.ActionBar; +import android.text.TextUtils; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.widget.Toast; + +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.account.activity.LoginActivity; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.base.activities.BaseBackActivity; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.bean.comment.Comment; +import net.oschina.app.improve.bean.comment.Reply; +import net.oschina.app.improve.bean.simple.About; +import net.oschina.app.improve.behavior.CommentBar; +import net.oschina.app.improve.tweet.adapter.TweetCommentAdapter; +import net.oschina.app.improve.tweet.service.TweetPublishService; +import net.oschina.app.improve.utils.DialogHelper; +import net.oschina.app.improve.widget.OWebView; +import net.oschina.app.ui.SelectFriendsActivity; +import net.oschina.app.util.StringUtils; +import net.oschina.app.util.TDevice; +import net.oschina.app.util.UIHelper; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import butterknife.Bind; +import butterknife.ButterKnife; +import butterknife.OnClick; +import cz.msebera.android.httpclient.Header; +import de.hdodenhof.circleimageview.CircleImageView; + +/** + * Created by thanatos + * on 16/6/16. + * change by fie + * on 16/11/17 + * desc:问答,活动的评论详情(相当于帖子),可以对评论进行顶踩操作 + */ +public class QuesAnswerDetailActivity extends BaseBackActivity { + + public static final String BUNDLE_KEY = "BUNDLE_KEY"; + public static final String BUNDLE_ARTICLE_KEY = "BUNDLE_ARTICLE_KEY"; + public static final String BUNDLE_TYPE = "bundle_comment_type"; + + @Bind(R.id.iv_portrait) + CircleImageView ivPortrait; + @Bind(R.id.tv_nick) + TextView tvNick; + @Bind(R.id.tv_time) + TextView tvTime; + @Bind(R.id.iv_vote_up) + ImageView ivVoteUp; + @Bind(R.id.iv_vote_down) + ImageView ivVoteDown; + @Bind(R.id.tv_up_count) + TextView tvVoteCount; + @Bind(R.id.webview) + OWebView mWebView; + @Bind(R.id.tv_comment_count) + TextView tvCmnCount; + @Bind(R.id.layout_container) + LinearLayout mLayoutContainer; + @Bind(R.id.layout_coordinator) + CoordinatorLayout mCoorLayout; + @Bind(R.id.layout_scroll) + NestedScrollView mScrollView; + + private long sid; + private Comment comment; + private int mType; + + private Dialog mVoteDialog; + private Dialog mWaitingDialog; + private Reply reply; + private View mVoteDialogView; + private List replies = new ArrayList<>(); + + private CommentBar mDelegation; + private TextHttpResponseHandler onSendCommentHandler; + private View.OnClickListener onReplyButtonClickListener; + + /** + * @param context context + * @param comment comment + * @param sid 文章id + */ + public static void show(Context context, Comment comment, long sid, int type) { + Intent intent = new Intent(context, QuesAnswerDetailActivity.class); + intent.putExtra(BUNDLE_KEY, comment); + intent.putExtra(BUNDLE_ARTICLE_KEY, sid); + intent.putExtra(BUNDLE_TYPE, type); + context.startActivity(intent); + } + + @Override + protected boolean initBundle(Bundle bundle) { + comment = (Comment) getIntent().getSerializableExtra(BUNDLE_KEY); + sid = getIntent().getLongExtra(BUNDLE_ARTICLE_KEY, 0); + mType = getIntent().getIntExtra(BUNDLE_TYPE, OSChinaApi.COMMENT_QUESTION); + return !(comment == null || comment.getId() <= 0) && super.initBundle(bundle); + } + + @Override + protected int getContentView() { + return R.layout.activity_post_answer_detail; + } + + @Override + protected void initWindow() { + super.initWindow(); + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setTitle(R.string.back_hint); + } + } + + @SuppressWarnings("deprecation") + protected void initWidget() { + // portrait + if (TextUtils.isEmpty(comment.getAuthor().getPortrait())) { + ivPortrait.setImageResource(R.mipmap.widget_dface); + } else { + getImageLoader() + .load(comment.getAuthor().getPortrait()) + .asBitmap() + .placeholder(getResources().getDrawable(R.mipmap.widget_dface)) + .error(getResources().getDrawable(R.mipmap.widget_dface)) + .into(ivPortrait); + } + + // nick + tvNick.setText(comment.getAuthor().getName()); + + // publish time + if (!TextUtils.isEmpty(comment.getPubDate())) + tvTime.setText(StringUtils.formatSomeAgo(comment.getPubDate())); + + // vote state + switch (comment.getVoteState()) { + case Comment.VOTE_STATE_UP: + ivVoteUp.setSelected(true); + break; + case Comment.VOTE_STATE_DOWN: + ivVoteDown.setSelected(true); + } + + // vote count + tvVoteCount.setText(String.valueOf(comment.getVote())); + + tvCmnCount.setText("评论 (" + (comment.getReply() == null ? 0 : comment.getReply().length) + ")"); + + mDelegation = CommentBar.delegation(this, mCoorLayout); + + mDelegation.hideFav(); + mDelegation.hideShare(); + + mDelegation.getBottomSheet().setMentionListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (AccountHelper.isLogin()) + SelectFriendsActivity.show(QuesAnswerDetailActivity.this); + else + LoginActivity.show(QuesAnswerDetailActivity.this); + } + }); + + mDelegation.getBottomSheet().setCommitListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + String content = mDelegation.getBottomSheet().getCommentText(); + if (TextUtils.isEmpty(content.replaceAll("[ \\s\\n]+", ""))) { + Toast.makeText(QuesAnswerDetailActivity.this, "请输入文字", Toast.LENGTH_SHORT).show(); + return; + } + if (!AccountHelper.isLogin()) { + UIHelper.showLoginActivity(QuesAnswerDetailActivity.this); + return; + } + + mWaitingDialog = DialogHelper.getProgressDialog(QuesAnswerDetailActivity.this, "正在发表评论...", false); + mWaitingDialog.show(); + + OSChinaApi.publishComment(sid, -1, comment.getId(), comment.getAuthor().getId(), 2, content, onSendCommentHandler); + } + }); + + mDelegation.getBottomSheet().getEditText().setOnKeyListener(new View.OnKeyListener() { + @Override + public boolean onKey(View v, int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_DEL && event.getAction() == KeyEvent.ACTION_DOWN) { + if (reply == null) return false; + reply = null; + mDelegation.setCommentHint("发表评论"); + mDelegation.getBottomSheet().getEditText().setHint("发表评论"); + } + return false; + } + }); + + Reply[] reply = comment.getReply(); + if (reply != null) { + mLayoutContainer.removeAllViews(); + replies.clear(); + Collections.addAll(replies, comment.getReply()); + Collections.reverse(replies); // 反转集合, 最新的评论在集合后面 + for (int i = 0; i < replies.size(); i++) { + appendComment(i, replies.get(i)); + } + } + + fillWebView(); + } + + private void fillWebView() { + if (TextUtils.isEmpty(comment.getContent())) return; + if (mWebView != null) + mWebView.loadDetailDataAsync(comment.getContent(), new Runnable() { + @Override + public void run() { + + } + }); + } + + @SuppressWarnings("deprecation") + private void appendComment(int i, Reply reply) { + View view = LayoutInflater.from(this).inflate(R.layout.list_item_tweet_comment, mLayoutContainer, false); + TweetCommentAdapter.TweetCommentHolderView holder = new TweetCommentAdapter.TweetCommentHolderView(view); + holder.tvName.setText(reply.getAuthor().getName()); + if (TextUtils.isEmpty(reply.getAuthor().getPortrait())) { + holder.ivPortrait.setImageResource(R.mipmap.widget_dface); + } else { + getImageLoader() + .load(reply.getAuthor().getPortrait()) + .asBitmap() + .placeholder(getResources().getDrawable(R.mipmap.widget_dface)) + .error(getResources().getDrawable(R.mipmap.widget_dface)) + .into(holder.ivPortrait); + } + holder.tvTime.setText(String.format("%s楼 %s", i + 1, StringUtils.formatSomeAgo(reply.getPubDate()))); + CommentsUtil.formatHtml(getResources(), holder.tvContent, reply.getContent()); + holder.btnReply.setTag(reply); + holder.btnReply.setOnClickListener(getOnReplyButtonClickListener()); + mLayoutContainer.addView(view, 0); + } + + private View.OnClickListener getOnReplyButtonClickListener() { + if (onReplyButtonClickListener == null) { + onReplyButtonClickListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + Reply reply = (Reply) v.getTag(); + + mDelegation.setCommentHint("回复 @" + reply.getAuthor().getName() + " : "); + + QuesAnswerDetailActivity.this.reply = reply; + } + }; + } + return onReplyButtonClickListener; + } + + protected void initData() { + onSendCommentHandler = new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + Toast.makeText(QuesAnswerDetailActivity.this, "评论失败", Toast.LENGTH_SHORT).show(); + if (mWaitingDialog != null) { + mWaitingDialog.dismiss(); + mWaitingDialog = null; + } + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + ResultBean result = AppOperator.createGson().fromJson( + responseString, + new TypeToken>() { + }.getType() + ); + if (result.isSuccess()) { + replies.add(result.getResult()); + tvCmnCount.setText("评论 (" + replies.size() + ")"); + reply = null; + mDelegation.setCommentHint("发表评论"); + mDelegation.getBottomSheet().getEditText().setHint("发表评论"); + appendComment(replies.size() - 1, result.getResult()); + boolean syncToTweet = mDelegation.getBottomSheet().isSyncToTweet(); + if (syncToTweet) { + TweetPublishService.startActionPublish(QuesAnswerDetailActivity.this, + mDelegation.getBottomSheet().getCommentText(), null, + About.buildShare(sid, mType)); + } + } else { + Toast.makeText(QuesAnswerDetailActivity.this, result.getMessage(), Toast.LENGTH_SHORT).show(); + } + mDelegation.getBottomSheet().dismiss(); + if (mWaitingDialog != null) { + mWaitingDialog.dismiss(); + mWaitingDialog = null; + } + } + + @Override + public void onFinish() { + super.onFinish(); + mDelegation.getBottomSheet().dismiss(); + } + }; + + OSChinaApi.getCommentDetail(comment.getId(), comment.getAuthor().getId(), mType, new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String respStr, Throwable throwable) { + Toast.makeText(QuesAnswerDetailActivity.this, "请求失败", Toast.LENGTH_SHORT).show(); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String respStr) { + ResultBean result = AppOperator.createGson().fromJson(respStr, + new TypeToken>() { + }.getType()); + if (result.isSuccess()) { + Comment cmn = result.getResult(); + if (cmn != null && cmn.getId() > 0) { + comment = cmn; + initWidget(); + return; + } + } + Toast.makeText(QuesAnswerDetailActivity.this, "请求失败", Toast.LENGTH_SHORT).show(); + } + }); + } + + @SuppressLint("InflateParams") + private View getVoteDialogView() { + if (mVoteDialogView == null) { + mVoteDialogView = LayoutInflater.from(this).inflate(R.layout.dialog_question_comment_detail_vote, null, false); + final VoteViewHolder holder = new VoteViewHolder(mVoteDialogView); + View.OnClickListener listener = new View.OnClickListener() { + @Override + public void onClick(final View v) { + if (!AccountHelper.isLogin()) { + UIHelper.showLoginActivity(QuesAnswerDetailActivity.this); + return; + } + final int opt = (int) v.getTag(); + switch (opt) { + case Comment.VOTE_STATE_UP: + if (ivVoteDown.isSelected()) { + Toast.makeText(QuesAnswerDetailActivity.this, "你已经踩过了", Toast.LENGTH_SHORT).show(); + return; + } + holder.mVoteUp.setVisibility(View.GONE); + holder.mProgressBar.setVisibility(View.VISIBLE); + break; + case Comment.VOTE_STATE_DOWN: + if (ivVoteUp.isSelected()) { + Toast.makeText(QuesAnswerDetailActivity.this, "你已经顶过了", Toast.LENGTH_SHORT).show(); + return; + } + holder.mVoteDown.setVisibility(View.GONE); + holder.mProgressBar.setVisibility(View.VISIBLE); + break; + } + OSChinaApi.questionVote(sid, comment.getId(), opt, new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + Toast.makeText(QuesAnswerDetailActivity.this, "操作失败", Toast.LENGTH_SHORT).show(); + if (mVoteDialog != null && mVoteDialog.isShowing()) { + switch (opt) { + case Comment.VOTE_STATE_UP: + holder.mVoteUp.setVisibility(View.VISIBLE); + holder.mProgressBar.setVisibility(View.GONE); + break; + case Comment.VOTE_STATE_DOWN: + holder.mVoteDown.setVisibility(View.VISIBLE); + holder.mProgressBar.setVisibility(View.GONE); + break; + } + } + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + ResultBean result = AppOperator.createGson().fromJson( + responseString, new TypeToken>() { + }.getType()); + if (result.isSuccess()) { + comment.setVoteState(result.getResult().getVoteState()); + comment.setVote((int) result.getResult().getVote()); + tvVoteCount.setText(String.valueOf(result.getResult().getVote())); + v.setSelected(!v.isSelected()); + switch (opt) { + case Comment.VOTE_STATE_UP: + ivVoteUp.setSelected(!ivVoteUp.isSelected()); + break; + case Comment.VOTE_STATE_DOWN: + ivVoteDown.setSelected(!ivVoteDown.isSelected()); + break; + } + Toast.makeText(QuesAnswerDetailActivity.this, "操作成功", Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(QuesAnswerDetailActivity.this, TextUtils.isEmpty(result.getMessage()) + ? "操作失败" : result.getMessage(), Toast.LENGTH_SHORT).show(); + } + if (mVoteDialog != null) mVoteDialog.dismiss(); + } + }); + } + }; + holder.mVoteUp.setTag(Comment.VOTE_STATE_UP); + holder.mVoteDown.setTag(Comment.VOTE_STATE_DOWN); + holder.mVoteUp.setOnClickListener(listener); + holder.mVoteDown.setOnClickListener(listener); + mVoteDialogView.setTag(holder); + } else { + ViewGroup view = (ViewGroup) mVoteDialogView.getParent(); + view.removeView(mVoteDialogView); + } + VoteViewHolder holder = (VoteViewHolder) mVoteDialogView.getTag(); + holder.mVoteDown.setVisibility(View.VISIBLE); + holder.mVoteUp.setVisibility(View.VISIBLE); + holder.mProgressBar.setVisibility(View.GONE); + switch (comment.getVoteState()) { + default: + holder.mVoteUp.setSelected(false); + holder.mVoteDown.setSelected(false); + holder.mVoteUp.setText("顶"); + holder.mVoteDown.setText("踩"); + break; + case Comment.VOTE_STATE_UP: + holder.mVoteUp.setSelected(true); + holder.mVoteDown.setSelected(false); + holder.mVoteUp.setText("已顶"); + holder.mVoteDown.setText("踩"); + break; + case Comment.VOTE_STATE_DOWN: + holder.mVoteUp.setSelected(false); + holder.mVoteDown.setSelected(true); + holder.mVoteUp.setText("顶"); + holder.mVoteDown.setText("已踩"); + break; + } + return mVoteDialogView; + } + + @SuppressWarnings("ConstantConditions") + @OnClick(R.id.layout_vote) + void onClickVote() { + mVoteDialog = DialogHelper.getDialog(this) + .setView(getVoteDialogView()) + .create(); + mVoteDialog.show(); + WindowManager.LayoutParams params = mVoteDialog.getWindow().getAttributes(); + params.width = (int) TDevice.dp2px(260f); + mVoteDialog.getWindow().setAttributes(params); + } + + public static class VoteViewHolder { + @Bind(R.id.btn_vote_up) + TextView mVoteUp; + @Bind(R.id.btn_vote_down) + TextView mVoteDown; + @Bind(R.id.progress) + ProgressBar mProgressBar; + + public VoteViewHolder(View view) { + ButterKnife.bind(this, view); + } + } + + @Override + protected void onDestroy() { + final OWebView webView = mWebView; + if (webView != null) { + mWebView = null; + webView.destroy(); + } + super.onDestroy(); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode == RESULT_OK && data != null) { + mDelegation.getBottomSheet().handleSelectFriendsResult(data); + mDelegation.setCommentHint(mDelegation.getBottomSheet().getEditText().getHint().toString()); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/comment/adapter/CommentAdapter.java b/app/src/main/java/net/oschina/app/improve/comment/adapter/CommentAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..f3822dea45d4f1c8c9bce6ceddf7459b54b40427 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/comment/adapter/CommentAdapter.java @@ -0,0 +1,333 @@ +package net.oschina.app.improve.comment.adapter; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.ProgressDialog; +import android.content.Context; +import android.support.annotation.StringRes; +import android.support.v7.widget.RecyclerView; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.bumptech.glide.RequestManager; +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.AppContext; +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.account.activity.LoginActivity; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.bean.comment.Comment; +import net.oschina.app.improve.bean.comment.Vote; +import net.oschina.app.improve.behavior.CommentBar; +import net.oschina.app.improve.comment.CommentReferView; +import net.oschina.app.improve.comment.CommentsUtil; +import net.oschina.app.improve.user.activities.OtherUserHomeActivity; +import net.oschina.app.improve.utils.DialogHelper; +import net.oschina.app.util.StringUtils; +import net.oschina.app.util.TDevice; +import net.oschina.app.widget.TweetTextView; + +import java.lang.reflect.Type; + +import butterknife.Bind; +import butterknife.ButterKnife; +import cz.msebera.android.httpclient.Header; +import de.hdodenhof.circleimageview.CircleImageView; + + +/** + * Created by fei + * on 2016/11/21. + * desc: + */ +public class CommentAdapter extends BaseRecyclerAdapter { + + private static final int VIEW_TYPE_DATA_FOOTER = 2000; + private long mSourceId; + + private int mType; + private CommentBar delegation; + + @Override + public int getItemViewType(int position) { + int type = super.getItemViewType(position); + if (type == VIEW_TYPE_NORMAL && isRealDataFooter(position)) { + return VIEW_TYPE_DATA_FOOTER; + } + return type; + } + + private boolean isRealDataFooter(int position) { + return getIndex(position) == getCount() - 1; + } + + private RequestManager mRequestManager; + + public CommentAdapter(final Context context, RequestManager requestManager, int mode) { + super(context, mode); + this.mRequestManager = requestManager; + } + + @Override + protected CommentHolder onCreateDefaultViewHolder(ViewGroup parent, int type) { + LayoutInflater inflater = LayoutInflater.from(parent.getContext()); + View view = inflater.inflate(R.layout.lay_comment_refer_item, parent, false); + return new CommentHolder(view, type == VIEW_TYPE_DATA_FOOTER, delegation); + } + + @Override + protected void onBindDefaultViewHolder(RecyclerView.ViewHolder holder, Comment item, int position) { + if (holder instanceof CommentHolder) { + ((CommentHolder) holder).addComment((position + 1), mSourceId, mType, item, mRequestManager); + } + } + + public void setSourceId(long sourceId) { + this.mSourceId = sourceId; + } + + public void setCommentType(int Type) { + this.mType = Type; + } + + public void setDelegation(CommentBar delegation) { + this.delegation = delegation; + } + + static class CommentHolder extends RecyclerView.ViewHolder { + + private ProgressDialog mDialog; + + @Bind(R.id.iv_avatar) + CircleImageView mIvAvatar; + + @Bind(R.id.tv_name) + TextView mName; + @Bind(R.id.tv_pub_date) + TextView mPubDate; + @Bind(R.id.tv_vote_count) + TextView mVoteCount; + @Bind(R.id.btn_vote) + ImageView mVote; + @Bind(R.id.btn_comment) + ImageView mComment; + + @Bind(R.id.lay_refer) + CommentReferView mCommentReferView; + + @Bind(R.id.tv_content) + TweetTextView mTweetTextView; + @Bind(R.id.line) + View mLine; + + private CommentBar commentBar; + + + CommentHolder(View itemView, boolean isFooter, CommentBar commentBar) { + super(itemView); + ButterKnife.bind(this, itemView); + //if (isFooter) { + // mLine.setVisibility(View.GONE); + //} + this.commentBar = commentBar; + } + + /** + * add comment + * + * @param comment comment + */ + @SuppressLint("DefaultLocale") + void addComment(int position, final long sourceId, final int commentType, final Comment comment, RequestManager requestManager) { + + requestManager.load(comment.getAuthor().getPortrait()).error(R.mipmap.widget_dface).into(mIvAvatar); + mIvAvatar.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + OtherUserHomeActivity.show(mIvAvatar.getContext(), comment.getAuthor().getId()); + } + }); + String name = comment.getAuthor().getName(); + if (TextUtils.isEmpty(name)) + name = mName.getResources().getString(R.string.martian_hint); + mName.setText(name); + mPubDate.setText(String.format("%d%s %s", position, mPubDate.getResources().getString(R.string.floor_hint), + StringUtils.formatSomeAgo(comment.getPubDate()))); + + mComment.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + if (!AccountHelper.isLogin()) { + LoginActivity.show((Activity) mComment.getContext(), 1); + return; + } + commentBar.getBottomSheet().getBtnCommit().setTag(comment); + + commentBar.getBottomSheet().show(String.format("%s %s", + mComment.getResources().getString(R.string.reply_hint), comment.getAuthor().getName())); + } + }); + + if (commentType == OSChinaApi.COMMENT_QUESTION || commentType == OSChinaApi.COMMENT_EVENT + || commentType == OSChinaApi.COMMENT_BLOG || commentType == OSChinaApi.COMMENT_TRANSLATION) { + mVoteCount.setVisibility(View.GONE); + mVote.setVisibility(View.GONE); + if (comment.isBest()) { + mComment.setImageResource(R.mipmap.label_best_answer); + mComment.setEnabled(false); + } else { + mComment.setEnabled(true); + mComment.setImageResource(R.mipmap.ic_comment_30); + } + } else { + mVoteCount.setText(String.valueOf(comment.getVote())); + mVoteCount.setVisibility(View.VISIBLE); + mVote.setVisibility(View.VISIBLE); + mComment.setEnabled(true); + if (comment.getVoteState() == 1) { + mVote.setImageResource(R.mipmap.ic_thumbup_actived); + mVote.setTag(true); + } else if (comment.getVoteState() == 0) { + mVote.setImageResource(R.mipmap.ic_thumb_normal); + mVote.setTag(null); + } + mVote.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + handVote(); + } + + private void handVote() { + if (!AccountHelper.isLogin()) { + LoginActivity.show(mVote.getContext()); + return; + } + if (!TDevice.hasInternet()) { + AppContext.showToast(mVote.getResources().getString(R.string.state_network_error), Toast.LENGTH_SHORT); + return; + } + OSChinaApi.voteComment(commentType, comment.getId(), comment.getAuthor().getId(), mVote.getTag() != null ? 0 : 1, new TextHttpResponseHandler() { + + @Override + public void onStart() { + super.onStart(); + showWaitDialog(R.string.progress_submit); + } + + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + requestFailureHint(throwable); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, getVoteType()); + if (resultBean.isSuccess()) { + Vote vote = resultBean.getResult(); + if (vote != null) { + if (vote.getVoteState() == 1) { + comment.setVoteState(1); + mVote.setTag(true); + mVote.setImageResource(R.mipmap.ic_thumbup_actived); + } else if (vote.getVoteState() == 0) { + comment.setVoteState(0); + mVote.setTag(null); + mVote.setImageResource(R.mipmap.ic_thumb_normal); + } + long voteVoteCount = vote.getVote(); + comment.setVote(voteVoteCount); + mVoteCount.setText(String.valueOf(voteVoteCount)); + } + } else { + AppContext.showToast(resultBean.getMessage(), Toast.LENGTH_SHORT); + } + } + + @Override + public void onFinish() { + super.onFinish(); + hideWaitDialog(); + } + }); + } + }); + } + + mCommentReferView.addComment(comment); + + CommentsUtil.formatHtml(mTweetTextView.getResources(), mTweetTextView, comment.getContent()); + } + + /** + * show WaitDialog + * + * @return progressDialog + */ + private ProgressDialog showWaitDialog(@StringRes int messageId) { + + if (mDialog == null) { + if (messageId <= 0) { + mDialog = DialogHelper.getProgressDialog(mVote.getContext(), true); + } else { + String message = mVote.getContext().getResources().getString(messageId); + mDialog = DialogHelper.getProgressDialog(mVote.getContext(), message, true); + } + } + mDialog.show(); + + return mDialog; + } + + + /** + * hide waitDialog + */ + private void hideWaitDialog() { + ProgressDialog dialog = mDialog; + if (dialog != null) { + mDialog = null; + try { + dialog.cancel(); + // dialog.dismiss(); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + } + + /** + * request network error + * + * @param throwable throwable + */ + private void requestFailureHint(Throwable throwable) { + AppContext.showToast(R.string.request_error_hint); + if (throwable != null) { + throwable.printStackTrace(); + } + } + + /** + * @return TypeToken + */ + Type getVoteType() { + return new TypeToken>() { + }.getType(); + } + + } + + +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/activities/BlogDetailActivity.java b/app/src/main/java/net/oschina/app/improve/detail/activities/BlogDetailActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..eeb68a51ababa0aa0838d028bc16eebc47402449 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/activities/BlogDetailActivity.java @@ -0,0 +1,217 @@ +package net.oschina.app.improve.detail.activities; + +import android.content.Context; +import android.content.Intent; +import android.text.TextUtils; +import android.view.Menu; +import android.view.View; + +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.AppContext; +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.bean.BlogDetail; +import net.oschina.app.improve.bean.Collection; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.bean.comment.Comment; +import net.oschina.app.improve.bean.simple.UserRelation; +import net.oschina.app.improve.comment.CommentsActivity; +import net.oschina.app.improve.detail.contract.BlogDetailContract; +import net.oschina.app.improve.detail.fragments.BlogDetailFragment; +import net.oschina.app.improve.detail.fragments.DetailFragment; + +import java.lang.reflect.Type; + +import cz.msebera.android.httpclient.Header; + +public class BlogDetailActivity extends DetailActivity + implements BlogDetailContract.Operator { + + public static void show(Context context, long id) { + Intent intent = new Intent(context, BlogDetailActivity.class); + intent.putExtra("id", id); + context.startActivity(intent); + } + + @Override + void requestData() { + OSChinaApi.getBlogDetail(getDataId(), getRequestHandler()); + } + + @Override + Class getDataViewFragment() { + return BlogDetailFragment.class; + } + + @Override + Type getDataType() { + return new TypeToken>() { + }.getType(); + } + + @Override + public void toFavorite() { + long uid = requestCheck(); + if (uid == 0) + return; + showWaitDialog(R.string.progress_submit); + final BlogDetail blogDetail = getData(); + OSChinaApi.getFavReverse(getDataId(), 3, new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + hideWaitDialog(); + if (blogDetail == null) + return; + if (blogDetail.isFavorite()) + AppContext.showToastShort(R.string.del_favorite_faile); + else + AppContext.showToastShort(R.string.add_favorite_faile); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + Type type = new TypeToken>() { + }.getType(); + + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, type); + if (resultBean != null && resultBean.isSuccess()) { + blogDetail.setFavorite(!blogDetail.isFavorite()); + mView.toFavoriteOk(blogDetail); + if (blogDetail.isFavorite()) + AppContext.showToastShort(R.string.add_favorite_success); + else + AppContext.showToastShort(R.string.del_favorite_success); + } + hideWaitDialog(); + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + } + }); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + boolean createOptionsMenu = super.onCreateOptionsMenu(menu); + if (createOptionsMenu) { + mCommentCountView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + CommentsActivity.show(BlogDetailActivity.this, mDataId, OSChinaApi.COMMENT_BLOG, OSChinaApi.COMMENT_NEW_ORDER); + } + }); + } + return createOptionsMenu; + } + + @Override + public void toShare() { + if (getData() != null) { + final BlogDetail detail = getData(); + String title = detail.getTitle(); + String content = detail.getBody(); + String url = detail.getHref(); + if (!toShare(title, content, url, 3)) + AppContext.showToast("抱歉,内容无法分享!"); + } else { + AppContext.showToast("内容加载失败!"); + } + } + + @Override + public void toFollow() { + long uid = requestCheck(); + if (uid == 0) + return; + showWaitDialog(R.string.progress_submit); + final BlogDetail blogDetail = getData(); + OSChinaApi.addUserRelationReverse(blogDetail.getAuthorId(), new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + AppContext.showToast("关注失败!"); + hideWaitDialog(); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + Type type = new TypeToken>() { + }.getType(); + + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, type); + if (resultBean != null && resultBean.isSuccess()) { + blogDetail.setAuthorRelation(resultBean.getResult().getRelation()); + mView.toFollowOk(blogDetail); + if (blogDetail.getAuthorRelation() >= 3) { + AppContext.showToast("取消关注成功"); + } else { + AppContext.showToast("关注成功"); + } + } + hideWaitDialog(); + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + hideWaitDialog(); + } + }); + } + + @Override + public void toSendComment(long id, long commentId, long commentAuthorId, String comment) { + long uid = requestCheck(); + if (uid == 0) + return; + + if (TextUtils.isEmpty(comment)) { + AppContext.showToastShort(R.string.tip_comment_content_empty); + return; + } + + OSChinaApi.pubBlogComment(id, commentId, commentAuthorId, comment, new TextHttpResponseHandler() { + + @Override + public void onStart() { + super.onStart(); + showWaitDialog(R.string.progress_submit); + } + + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + AppContext.showToast(getResources().getString(R.string.pub_comment_failed)); + hideWaitDialog(); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + Type type = new TypeToken>() { + }.getType(); + + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, type); + if (resultBean.isSuccess()) { + Comment respComment = resultBean.getResult(); + if (respComment != null) { + BlogDetailContract.View view = mView; + if (view != null) { + view.toSendCommentOk(respComment); + } + } + } + hideWaitDialog(); + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + hideWaitDialog(); + } + }); + } + +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/activities/DetailActivity.java b/app/src/main/java/net/oschina/app/improve/detail/activities/DetailActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..a4607353e2f5da1e4a6e801d6446d0e938f89095 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/activities/DetailActivity.java @@ -0,0 +1,421 @@ +package net.oschina.app.improve.detail.activities; + +import android.app.ProgressDialog; +import android.content.DialogInterface; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentTransaction; +import android.support.v7.app.AlertDialog; +import android.text.TextUtils; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; +import android.widget.TextView; +import android.widget.Toast; + +import com.loopj.android.http.AsyncHttpResponseHandler; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.AppContext; +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.bean.Report; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.base.activities.BaseBackActivity; +import net.oschina.app.improve.bean.PrimaryBean; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.detail.contract.DetailContract; +import net.oschina.app.improve.detail.fragments.DetailFragment; +import net.oschina.app.improve.dialog.ShareDialogBuilder; +import net.oschina.app.improve.utils.DialogHelper; +import net.oschina.app.ui.ReportDialog; +import net.oschina.app.ui.empty.EmptyLayout; +import net.oschina.app.util.HTMLUtil; +import net.oschina.app.util.StringUtils; +import net.oschina.app.util.TDevice; +import net.oschina.app.util.UIHelper; + +import java.lang.reflect.Type; + +import cz.msebera.android.httpclient.Header; + +/** + * Created by JuQiu + * on 16/6/20. + */ + +public abstract class DetailActivity extends + BaseBackActivity + implements DetailContract.Operator { + + long mDataId; + Data mData; + DataView mView; + EmptyLayout mEmptyLayout; + TextView mCommentCountView; + + private ProgressDialog mDialog; + private ShareDialogBuilder mShareDialogBuilder; + private AlertDialog alertDialog; + + public long getDataId() { + return mData != null ? mData.getId() : mDataId; + } + + public Data getData() { + return mData; + } + + @Override + protected int getContentView() { + return R.layout.activity_blog_detail; + } + + @Override + public void setDataView(DataView view) { + mView = view; + } + + @Override + protected boolean initBundle(Bundle bundle) { + super.initBundle(bundle); + mDataId = bundle.getLong("id", 0); + return mDataId != 0; + } + + @Override + protected void initWidget() { + super.initWidget(); + mEmptyLayout = (EmptyLayout) findViewById(R.id.lay_error); + mEmptyLayout.setOnLayoutClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + EmptyLayout emptyLayout = mEmptyLayout; + if (emptyLayout != null && emptyLayout.getErrorState() != EmptyLayout.HIDE_LAYOUT) { + emptyLayout.setErrorType(EmptyLayout.NETWORK_LOADING); + requestData(); + } + } + }); + } + + @SuppressWarnings("deprecation") + public ProgressDialog showWaitDialog(int messageId) { + String message = getResources().getString(messageId); + if (mDialog == null) { + mDialog = DialogHelper.getProgressDialog(this, message); + } + + mDialog.setMessage(message); + mDialog.show(); + + return mDialog; + } + + public void hideWaitDialog() { + ProgressDialog dialog = mDialog; + if (dialog != null) { + mDialog = null; + try { + dialog.dismiss(); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + } + + @Override + protected void initData() { + super.initData(); + requestData(); + } + + @Override + public void hideLoading() { + final EmptyLayout emptyLayout = mEmptyLayout; + if (emptyLayout == null) + return; + Animation animation = AnimationUtils.loadAnimation(this, R.anim.anim_alpha_to_hide); + animation.setAnimationListener(new Animation.AnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + + } + + @Override + public void onAnimationEnd(Animation animation) { + emptyLayout.setErrorType(EmptyLayout.HIDE_LAYOUT); + } + + @Override + public void onAnimationRepeat(Animation animation) { + + } + }); + emptyLayout.startAnimation(animation); + } + + /** + * 请求数据 + */ + abstract void requestData(); + + /** + * 获取显示界面的Fragment + * + * @return 继承自DetailFragment + */ + abstract Class getDataViewFragment(); + + /** + * 得到JSON解析的数据Type + * + * @return Type + */ + abstract Type getDataType(); + + AsyncHttpResponseHandler getRequestHandler() { + return new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, + Throwable throwable) { + throwable.printStackTrace(); + if (isDestroy()) + return; + showError(EmptyLayout.NETWORK_ERROR); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + if (isDestroy()) + return; + if (!handleData(responseString)) + showError(EmptyLayout.NODATA); + } + }; + } + + @SuppressWarnings("TryWithIdenticalCatches") + void handleView() { + try { + Fragment fragment = getDataViewFragment().newInstance(); + FragmentTransaction trans = getSupportFragmentManager() + .beginTransaction(); + trans.replace(R.id.lay_container, fragment); + trans.commit(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + + boolean handleData(String responseString) { + ResultBean result; + try { + Type type = getDataType(); + result = AppOperator.createGson().fromJson(responseString, type); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + + if (result.isSuccess() && result.getResult().getId() != 0) { + mData = result.getResult(); + handleView(); + return true; + } + + return false; + + } + + void showError(int type) { + EmptyLayout layout = mEmptyLayout; + if (layout != null) { + layout.setErrorType(type); + } + } + + @Override + public void setCommentCount(int count) { + final TextView view = mCommentCountView; + if (view != null) { + String str; + if (count < 1000) + str = String.valueOf(count); + else if (count < 10000) { + str = String.format("%sK", (Math.round(count * 0.01f) * 0.1f)); + } else { + str = String.format("%sW", (Math.round(count * 0.001f) * 0.1f)); + } + view.setText(str); + } + } + + int getOptionsMenuId() { + return R.menu.menu_detail; + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + int menuId = getOptionsMenuId(); + if (menuId <= 0) + return false; + MenuInflater inflater = getMenuInflater(); + inflater.inflate(menuId, menu); + MenuItem item = menu.findItem(R.id.menu_scroll_comment); + if (item != null) { + View action = item.getActionView(); + if (action != null) { + action.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + DataView view = mView; + if (view != null) { + view.scrollToComment(); + } + } + }); + View tv = action.findViewById(R.id.tv_comment_count); + if (tv != null) + mCommentCountView = (TextView) tv; + } + } + return true; + } + + /** + * 分享传递原始数据进入,截取前55个文字 + * + * @param title 标题 + * @param content 分享内容 + * @param url 分享地址 + */ + protected boolean toShare(String title, String content, String url, int type) { + if (TextUtils.isEmpty(title) || TextUtils.isEmpty(content) || TextUtils.isEmpty(url)) + return false; + + content = content.trim(); + if (content.length() > 55) { + content = HTMLUtil.delHTMLTag(content); + if (content.length() > 55) + content = StringUtils.getSubString(0, 55, content); + } else { + content = HTMLUtil.delHTMLTag(content); + } + if (TextUtils.isEmpty(content)) + return false; + + // 分享 + if (mShareDialogBuilder == null) { + mShareDialogBuilder = ShareDialogBuilder.with(this) + .id(getDataId()) + .type(type) + .title(title) + .content(content) + .url(url) + .build(); + } + if (alertDialog == null) + alertDialog = mShareDialogBuilder.create(); + alertDialog.show(); + return true; + } + + + protected void toReport(long id, String href, byte reportType) { + + final ReportDialog dialog = new ReportDialog(this, href, id, reportType); + dialog.setCancelable(true); + dialog.setTitle(R.string.report); + dialog.setCanceledOnTouchOutside(true); + dialog.setNegativeButton(R.string.cancle, null); + final TextHttpResponseHandler handler = new TextHttpResponseHandler() { + + @Override + public void onSuccess(int arg0, Header[] arg1, String arg2) { + if (TextUtils.isEmpty(arg2)) { + AppContext.showToastShort(R.string.tip_report_success); + } else { + AppContext.showToastShort(arg2); + } + } + + @Override + public void onFailure(int arg0, Header[] arg1, String arg2, + Throwable arg3) { + AppContext.showToastShort(R.string.tip_report_faile); + } + + @Override + public void onFinish() { + hideWaitDialog(); + } + + @Override + public void onStart() { + showWaitDialog(R.string.progress_submit); + } + }; + dialog.setPositiveButton(R.string.ok, + new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface d, int which) { + Report report; + if ((report = dialog.getReport()) != null) { + OSChinaApi.report(report, handler); + } + d.dismiss(); + } + }); + dialog.show(); + } + + /** + * 检查当前数据,并检查网络状况 + * + * @return 返回当前登录用户, 未登录或者未通过检查返回0 + */ + public long requestCheck() { + if (mDataId == 0 && mData == null) { + AppContext.showToast(getResources().getString(R.string.state_loading_error), Toast.LENGTH_SHORT); + return 0; + } + if (!TDevice.hasInternet()) { + AppContext.showToastShort(R.string.tip_no_internet); + return 0; + } + if (!AccountHelper.isLogin()) { + UIHelper.showLoginActivity(this); + return 0; + } + // 返回当前登录用户ID + return AccountHelper.getUserId(); + } + + @Override + protected void onResume() { + super.onResume(); + if (mShareDialogBuilder != null) { + mShareDialogBuilder.cancelLoading(); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + hideWaitDialog(); + // hideShareDialog(); + mEmptyLayout = null; + mData = null; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/activities/EventDetailActivity.java b/app/src/main/java/net/oschina/app/improve/detail/activities/EventDetailActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..d9fcfd8b28bd668416e76f158e912101cd906bac --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/activities/EventDetailActivity.java @@ -0,0 +1,164 @@ +package net.oschina.app.improve.detail.activities; + +import android.content.Context; +import android.content.Intent; +import android.view.MenuItem; + +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.AsyncHttpResponseHandler; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.AppContext; +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.bean.EventApplyData; +import net.oschina.app.bean.Result; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.bean.Collection; +import net.oschina.app.improve.bean.EventDetail; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.detail.contract.EventDetailContract; +import net.oschina.app.improve.detail.fragments.DetailFragment; +import net.oschina.app.improve.detail.fragments.EventDetailFragment; +import net.oschina.app.util.UIHelper; +import net.oschina.app.util.XmlUtils; + +import java.io.ByteArrayInputStream; +import java.lang.reflect.Type; + +import cz.msebera.android.httpclient.Header; + +/** + * Created by huanghaibin + * on 16-6-13. + */ +public class EventDetailActivity extends DetailActivity implements EventDetailContract.Operator { + + public static void show(Context context, long id) { + Intent intent = new Intent(context, EventDetailActivity.class); + intent.putExtra("id", id); + context.startActivity(intent); + } + + + @Override + protected void initData() { + super.initData(); + } + + @Override + void requestData() { + OSChinaApi.getEventDetail(mDataId, getRequestHandler()); + } + + @Override + Class getDataViewFragment() { + return EventDetailFragment.class; + } + + @Override + Type getDataType() { + return new TypeToken>() { + }.getType(); + } + + @Override + int getOptionsMenuId() { + return R.menu.menu_detail_share; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == R.id.menu_share) { + final EventDetail detail = getData(); + if (detail != null) { + toShare(detail.getTitle(), detail.getBody(), detail.getHref(), 5); + } + } + return super.onOptionsItemSelected(item); + } + + @Override + public void toFav() { + if (!isLogin()) + return; + final EventDetail mDetail = getData(); + OSChinaApi.getFavReverse(mDataId, 5, new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + hideWaitDialog(); + if (mDetail.isFavorite()) + AppContext.showToastShort(R.string.del_favorite_faile); + else + AppContext.showToastShort(R.string.add_favorite_faile); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + Type type = new TypeToken>() { + }.getType(); + + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, type); + if (resultBean != null && resultBean.isSuccess()) { + mDetail.setFavorite(!mDetail.isFavorite()); + mView.toFavOk(mDetail); + if (mDetail.isFavorite()) + AppContext.showToastShort(R.string.add_favorite_success); + else + AppContext.showToastShort(R.string.del_favorite_success); + } + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + hideWaitDialog(); + } + }); + } + + @Override + public void toSignUp(EventApplyData data) { + if (!isLogin()) + return; + final EventDetail mDetail = getData(); + showWaitDialog(R.string.progress_submit); + OSChinaApi.eventApply(data, new AsyncHttpResponseHandler() { + @Override + public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { + Result rs = XmlUtils.toBean(net.oschina.app.bean.ResultBean.class, + new ByteArrayInputStream(responseBody)).getResult(); + if (rs.OK()) { + AppContext.showToast("报名成功"); + mDetail.setApplyStatus(0); + mView.toSignUpOk(mDetail); + } else { + AppContext.showToast(rs.getErrorMessage()); + } + hideWaitDialog(); + } + + @Override + public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { + hideWaitDialog(); + } + }); + } + + private boolean isLogin() { + if (!AccountHelper.isLogin()) { + UIHelper.showLoginActivity(this); + return false; + } + return true; + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode == RESULT_OK) { + requestData(); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/activities/EventSigninActivity.java b/app/src/main/java/net/oschina/app/improve/detail/activities/EventSigninActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..539d50f12413666a7dec9e614df18698a378eb5f --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/activities/EventSigninActivity.java @@ -0,0 +1,507 @@ +package net.oschina.app.improve.detail.activities; + +import android.annotation.SuppressLint; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.StringRes; +import android.text.Editable; +import android.text.TextUtils; +import android.view.View; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.AppContext; +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.base.activities.BaseBackActivity; +import net.oschina.app.improve.bean.Event; +import net.oschina.app.improve.bean.EventDetail; +import net.oschina.app.improve.bean.EventSignin; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.utils.AssimilateUtils; +import net.oschina.app.improve.utils.DialogHelper; +import net.oschina.app.improve.widget.listenerAdapter.TextWatcherAdapter; +import net.oschina.app.ui.empty.EmptyLayout; +import net.oschina.app.util.TDevice; + +import java.util.Map; +import java.util.Set; + +import butterknife.Bind; +import cz.msebera.android.httpclient.Header; + +/** + * Created by fei + * on 2016/11/30. + * change by fei + * on 2016/12/15 + * desc:活动签到 + */ + +public class EventSigninActivity extends BaseBackActivity { + + public static final String EVENT_ID_KEY = "event_id_key"; + + @Bind(R.id.iv_event_img) + ImageView mIvImg; + @Bind(R.id.tv_event_title) + TextView mTvTitle; + @Bind(R.id.tv_event_author) + TextView mTvAuthor; + @Bind(R.id.tv_event_type) + TextView mTvType; + @Bind(R.id.tv_event_counts) + TextView mTvCounts; + + @Bind(R.id.ck_check) + CheckBox mCkLabel; + + @Bind(R.id.line) + View mLine; + + @Bind(R.id.lay_input_bg) + LinearLayout mLayInputBg; + + @Bind(R.id.et_signin) + EditText mEtSignin; + + @Bind(R.id.lay_container_user_info) + LinearLayout mLayUserInfo; + + @Bind(R.id.tv_signin_notice) + TextView mTvNotice; + + @Bind(R.id.bt_signin_submit) + Button mBtSubmit; + + @Bind(R.id.lay_error) + EmptyLayout mEmptyLayout; + + private long mId; + private int mRequestType = 0x01;//0x01 请求活动详情 0x02 匹配当前账户信息是否是报名账户 0x03 签到 + private ProgressDialog mDialog; + + private EventDetail mEventDetail = null; + + /** + * show signinActivity + * + * @param context context + */ + public static void show(Context context, long sourceId) { + Intent intent = new Intent(context, EventSigninActivity.class); + intent.putExtra(EVENT_ID_KEY, sourceId); + context.startActivity(intent); + } + + @Override + protected int getContentView() { + return R.layout.activity_main_signin; + } + + @Override + protected boolean initBundle(Bundle bundle) { + mId = bundle.getLong(EVENT_ID_KEY, 0); + return mId > 0; + } + + @SuppressWarnings("deprecation") + @Override + protected void initWidget() { + super.initWidget(); + + mEtSignin.addTextChangedListener(new TextWatcherAdapter() { + @SuppressWarnings("deprecation") + @Override + public void afterTextChanged(Editable s) { + String input = s.toString().trim(); + boolean machPhoneNum = AssimilateUtils.machPhoneNum(input); + mLayInputBg.setActivated(true); + if (machPhoneNum) { + mBtSubmit.setEnabled(true); + mLayInputBg.setBackgroundResource(R.drawable.bg_signin_input_ok); + } else { + if (s.length() <= 0) { + mLayInputBg.setBackgroundResource(R.drawable.bg_signin_input_ok); + } else { + mLayInputBg.setBackgroundResource(R.drawable.bg_signin_input_error); + } + mBtSubmit.setEnabled(false); + } + } + }); + + mEmptyLayout.setOnLayoutClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + EmptyLayout emptyLayout = mEmptyLayout; + if (emptyLayout != null && emptyLayout.getErrorState() != EmptyLayout.HIDE_LAYOUT) { + emptyLayout.setErrorType(EmptyLayout.NETWORK_LOADING); + requestData(); + } + } + }); + + mBtSubmit.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + submitToSignIn(); + } + }); + + mIvImg.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + EventDetailActivity.show(EventSigninActivity.this, mId); + } + }); + } + + @SuppressWarnings("deprecation") + @Override + protected void initData() { + super.initData(); + + //检查网络 + if (!checkNetIsAvailable()) { + showError(EmptyLayout.NETWORK_ERROR); + return; + } + + requestData(); + } + + private boolean checkNetIsAvailable() { + if (!TDevice.hasInternet()) { + AppContext.showToastShort(getString(R.string.tip_network_error)); + showError(EmptyLayout.NETWORK_ERROR); + return false; + } + return true; + } + + private void requestData() { + int requestType = mRequestType; + switch (requestType) { + case 0x01: + requestEventDetail(mId); + break; + case 0x02: + requestApplyInfo(mEventDetail, mId); + break; + default: + break; + } + } + + private void submitToSignIn() { + if (!checkNetIsAvailable()) return; + String phone = mEtSignin.getText().toString().trim(); + OSChinaApi.eventSignin(mId, phone, new TextHttpResponseHandler() { + @Override + public void onStart() { + super.onStart(); + showFocusWaitDialog(R.string.state_submit); + } + + @Override + public void onFinish() { + super.onFinish(); + hideWaitDialog(); + } + + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + AppContext.showToastShort(R.string.state_network_error); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + //签到成功更新数据 + ResultBean signinResultBean = AppOperator.createGson().fromJson(responseString, + new TypeToken>() { + }.getType()); + if (signinResultBean.isSuccess()) { + EventSignin eventSignin = signinResultBean.getResult(); + updateSigninView(eventSignin); + } + } + }); + } + + private void requestEventDetail(final long sourceId) { + //1.第一次初始化活动详情数据 + OSChinaApi.getEventDetail(sourceId, new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + showError(EmptyLayout.NETWORK_ERROR); + } + + @SuppressWarnings("deprecation") + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, + new TypeToken>() { + }.getType()); + + if (resultBean.isSuccess()) { + EventDetail eventDetail = resultBean.getResult(); + + if (eventDetail.getId() <= 0) { + AppContext.showToastShort(getString(R.string.event_null_hint)); + showError(EmptyLayout.NODATA); + return; + } + + mEventDetail = eventDetail; + + if (AccountHelper.isLogin()) { + if (!checkNetIsAvailable()) return; + mRequestType = 0x02; + //2.如果是登录状态,需要匹配是否是该账户的报名信息 + requestApplyInfo(eventDetail, sourceId); + } else { + mRequestType = 0x03; + updateDetailView(eventDetail); + mLayInputBg.setActivated(true); + mBtSubmit.setEnabled(false); + hideLoading(); + } + } else { + showError(EmptyLayout.NODATA); + } + } + }); + } + + private void requestApplyInfo(final EventDetail eventDetail, long sourceId) { + OSChinaApi.syncSignUserInfo(sourceId, new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + showError(EmptyLayout.NETWORK_ERROR); + } + + @SuppressWarnings("deprecation") + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + + ResultBean> mapResultBean = AppOperator.createGson().fromJson(responseString, + new TypeToken>>() { + }.getType()); + + mRequestType = 0x03; + int code = mapResultBean.getCode(); + + switch (code) { + case 0: + //code=0,请求不到相关数据,直接使用手机号报名(ps:有可能使用的是其他账户或者直接手机号报名的情况) + updateDetailView(eventDetail); + setTelVisible(View.VISIBLE); + mLayInputBg.setActivated(true); + mBtSubmit.setEnabled(false); + hideLoading(); + break; + case 1: + //code=1,请求成功 + Map userInfoMap = mapResultBean.getResult(); + if (userInfoMap != null && userInfoMap.size() > 0) { + //显示相关报名的用户数据 + updateDetailView(eventDetail); + setTelVisible(View.GONE); + updateUserInfoView(userInfoMap); + mBtSubmit.setEnabled(true); + hideLoading(); + } else { + //报名所填相关用户数据全为null,但是却是报名了的 + updateDetailView(eventDetail); + setTelVisible(View.GONE); + mBtSubmit.setEnabled(true); + hideLoading(); + } + break; + case 404: + //code=404,当前登录的用户未报名该活动,返回相关数据为null + updateDetailView(eventDetail); + setTelVisible(View.VISIBLE); + mLayInputBg.setActivated(true); + mBtSubmit.setEnabled(false); + hideLoading(); + AppContext.showToastShort(mapResultBean.getMessage()); + break; + default: + AppContext.showToastShort(mapResultBean.getMessage()); + showError(EmptyLayout.NODATA); + break; + } + } + }); + } + + private void setTelVisible(int visible) { + mCkLabel.setVisibility(visible); + mLine.setVisibility(View.INVISIBLE); + mLayInputBg.setVisibility(visible); + } + + @SuppressLint("DefaultLocale") + private void updateDetailView(EventDetail eventDetail) { + + if (eventDetail.getImg() != null) + getImageLoader().load(eventDetail.getImg()).into(mIvImg); + + mTvTitle.setText(eventDetail.getTitle()); + + if (eventDetail.getAuthor() != null) + mTvAuthor.setText(String.format("%s %s", getString(R.string.signin_event_author), eventDetail.getAuthor())); + + int typeStr = R.string.oscsite; + + switch (eventDetail.getType()) { + case Event.EVENT_TYPE_OSC: + typeStr = R.string.event_type_osc; + break; + case Event.EVENT_TYPE_TEC: + typeStr = R.string.event_type_tec; + break; + case Event.EVENT_TYPE_OTHER: + typeStr = R.string.event_type_other; + break; + case Event.EVENT_TYPE_OUTSIDE: + typeStr = R.string.event_type_outside; + break; + } + + mTvType.setText(String.format("%s:%s", getString(R.string.signin_event_type_hint), getString(typeStr))); + mTvCounts.setText(String.format("%d%s", eventDetail.getViewCount(), getString(R.string.signin_event_counts_hint))); + + if (!AccountHelper.isLogin()) { + setTelVisible(View.VISIBLE); + } else { + setTelVisible(View.GONE); + } + } + + + private void updateUserInfoView(Map userInfo) { + + Set> entries = userInfo.entrySet(); + + for (Map.Entry next : entries) { + + String key = next.getKey(); + String value = next.getValue(); + + if (TextUtils.isEmpty(value) || TextUtils.isEmpty(key)) { + continue; + } + + @SuppressLint("InflateParams") View rootView = getLayoutInflater().inflate(R.layout.lay_signin_user_info, null, false); + TextView tvKey = (TextView) rootView.findViewById(R.id.tv_key); + tvKey.setText(String.format("%s:", key)); + TextView tvValue = (TextView) rootView.findViewById(R.id.tv_value); + tvValue.setText(value); + mLayUserInfo.addView(rootView); + } + } + + + /** + * update event signin view + * + * @param eventSignin eventSignin + */ + private void updateSigninView(EventSignin eventSignin) { + int optStatus = eventSignin.getOptStatus(); + switch (optStatus) { + case 0x01://签到成功 + case 0x03://活动已结束/活动报名已截止 + case 0x04://您已签到 + mCkLabel.setVisibility(View.GONE); + mLayInputBg.setVisibility(View.GONE); + mTvNotice.setVisibility(View.VISIBLE); + mTvNotice.setText(eventSignin.getMessage()); + mLayUserInfo.setVisibility(View.GONE); + break; + case 0x02://活动进行中未报名 + AppContext.showToastShort(eventSignin.getMessage()); + break; + default: + break; + } + } + + public void hideLoading() { + final EmptyLayout emptyLayout = mEmptyLayout; + if (emptyLayout == null) + return; + Animation animation = AnimationUtils.loadAnimation(this, R.anim.anim_alpha_to_hide); + animation.setAnimationListener(new Animation.AnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + + } + + @Override + public void onAnimationEnd(Animation animation) { + emptyLayout.setErrorType(EmptyLayout.HIDE_LAYOUT); + } + + @Override + public void onAnimationRepeat(Animation animation) { + + } + }); + emptyLayout.startAnimation(animation); + } + + private void showError(int type) { + EmptyLayout layout = mEmptyLayout; + if (layout != null) { + layout.setErrorType(type); + } + } + + /** + * show FocusWaitDialog + * + * @return progressDialog + */ + private ProgressDialog showFocusWaitDialog(@StringRes int messageId) { + + String message = getResources().getString(messageId); + if (mDialog == null) { + mDialog = DialogHelper.getProgressDialog(this, message, false);//DialogHelp.getWaitDialog(this, message); + } + mDialog.show(); + + return mDialog; + } + + /** + * hide waitDialog + */ + private void hideWaitDialog() { + ProgressDialog dialog = mDialog; + if (dialog != null) { + mDialog = null; + try { + dialog.cancel(); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/activities/NewsDetailActivity.java b/app/src/main/java/net/oschina/app/improve/detail/activities/NewsDetailActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..c9d7eed778b6b7d4cffe5d8a48f33ea062bef504 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/activities/NewsDetailActivity.java @@ -0,0 +1,194 @@ +package net.oschina.app.improve.detail.activities; + +import android.content.Context; +import android.content.Intent; +import android.text.TextUtils; +import android.view.Menu; +import android.view.View; + +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.AppContext; +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.bean.Collection; +import net.oschina.app.improve.bean.NewsDetail; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.bean.comment.Comment; +import net.oschina.app.improve.comment.CommentsActivity; +import net.oschina.app.improve.detail.contract.NewsDetailContract; +import net.oschina.app.improve.detail.fragments.DetailFragment; +import net.oschina.app.improve.detail.fragments.NewsDetailFragment; + +import java.lang.reflect.Type; + +import cz.msebera.android.httpclient.Header; + +/** + * Created by fei on 2016/6/13. + * desc: news detail module + */ +public class NewsDetailActivity extends DetailActivity + implements NewsDetailContract.Operator { + + /** + * show news detail + * + * @param context context + * @param id id + */ + public static void show(Context context, long id) { + Intent intent = new Intent(context, NewsDetailActivity.class); + intent.putExtra("id", id); + context.startActivity(intent); + } + + int getType() { + return 6; + } + + @Override + protected int getContentView() { + return R.layout.activity_blog_detail; + } + + @Override + void requestData() { + OSChinaApi.getNewsDetail(getDataId(), OSChinaApi.CATALOG_NEWS_DETAIL, getRequestHandler()); + } + + @Override + Class getDataViewFragment() { + return NewsDetailFragment.class; + } + + @Override + Type getDataType() { + return new TypeToken>() { + }.getType(); + } + + @Override + public void toFavorite() { + long uid = requestCheck(); + if (uid == 0) + return; + showWaitDialog(R.string.progress_submit); + final NewsDetail newsDetail = getData(); + OSChinaApi.getFavReverse(getDataId(), getType(), new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + hideWaitDialog(); + if (newsDetail.isFavorite()) + AppContext.showToastShort(R.string.del_favorite_faile); + else + AppContext.showToastShort(R.string.add_favorite_faile); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + Type type = new TypeToken>() { + }.getType(); + + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, type); + if (resultBean != null && resultBean.isSuccess()) { + newsDetail.setFavorite(!newsDetail.isFavorite()); + mView.toFavoriteOk(newsDetail); + if (newsDetail.isFavorite()) + AppContext.showToastShort(R.string.add_favorite_success); + else + AppContext.showToastShort(R.string.del_favorite_success); + } + hideWaitDialog(); + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + } + }); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + boolean createOptionsMenu = super.onCreateOptionsMenu(menu); + if (createOptionsMenu) { + mCommentCountView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + CommentsActivity.show(NewsDetailActivity.this, mDataId, OSChinaApi.COMMENT_NEWS, OSChinaApi.COMMENT_NEW_ORDER); + } + }); + } + return createOptionsMenu; + } + + @Override + public void toShare() { + if (getData() != null) { + final NewsDetail detail = getData(); + String title = detail.getTitle(); + String content = detail.getBody(); + String url = detail.getHref(); + if (!toShare(title, content, url, 6)) + AppContext.showToast("抱歉,内容无法分享!"); + } else { + AppContext.showToast("内容加载失败!"); + } + } + + + @Override + public void toSendComment(long id, long commentId, long commentAuthorId, String comment) { + long uid = requestCheck(); + if (uid == 0) + return; + + if (TextUtils.isEmpty(comment)) { + AppContext.showToastShort(R.string.tip_comment_content_empty); + return; + } + OSChinaApi.pubNewsComment(id, commentId, commentAuthorId, comment, new TextHttpResponseHandler() { + + @Override + public void onStart() { + super.onStart(); + showWaitDialog(R.string.progress_submit); + } + + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + AppContext.showToast("评论失败!"); + hideWaitDialog(); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + + try { + Type type = new TypeToken>() { + }.getType(); + + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, type); + if (resultBean.isSuccess()) { + Comment respComment = resultBean.getResult(); + if (respComment != null) { + NewsDetailContract.View view = mView; + if (view != null) { + view.toSendCommentOk(respComment); + } + } + } + hideWaitDialog(); + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + hideWaitDialog(); + } + }); + + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/activities/QuestionDetailActivity.java b/app/src/main/java/net/oschina/app/improve/detail/activities/QuestionDetailActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..442a9f787dde072f9b86edcd6898c53090cf98fc --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/activities/QuestionDetailActivity.java @@ -0,0 +1,202 @@ +package net.oschina.app.improve.detail.activities; + +import android.content.Context; +import android.content.Intent; +import android.text.TextUtils; +import android.view.MenuItem; + +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.AppContext; +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.bean.Report; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.bean.Collection; +import net.oschina.app.improve.bean.QuestionDetail; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.bean.comment.Comment; +import net.oschina.app.improve.detail.contract.QuestionDetailContract; +import net.oschina.app.improve.detail.fragments.DetailFragment; +import net.oschina.app.improve.detail.fragments.QuestionDetailFragment; + +import java.lang.reflect.Type; + +import cz.msebera.android.httpclient.Header; + +/** + * Created by fei on 2016/6/13. + * desc: question detail module + */ +public class QuestionDetailActivity extends DetailActivity implements QuestionDetailContract.Operator { + + public static void show(Context context, long id) { + Intent intent = new Intent(context, QuestionDetailActivity.class); + intent.putExtra("id", id); + context.startActivity(intent); + } + + @Override + int getOptionsMenuId() { + return R.menu.menu_detail_report; + } + +// @Override +// public boolean onCreateOptionsMenu(Menu menu) { +// boolean createOptionsMenu = super.onCreateOptionsMenu(menu); +// if (createOptionsMenu) { +// mCommentCountView.setOnClickListener(new View.OnClickListener() { +// @Override +// public void onClick(View v) { +// CommentsActivity.show(QuestionDetailActivity.this, mDataId, 2); +// } +// }); +// } +// return createOptionsMenu; +// } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + int id = item.getItemId(); + if (id == R.id.menu_report) { + toReport(); + } + return super.onOptionsItemSelected(item); + } + + @Override + void requestData() { + OSChinaApi.getQuestionDetail(getDataId(), getRequestHandler()); + } + + @Override + Class getDataViewFragment() { + return QuestionDetailFragment.class; + } + + @Override + Type getDataType() { + return new TypeToken>() { + }.getType(); + } + + + @Override + public void toFavorite() { + long uid = requestCheck(); + if (uid == 0) + return; + showWaitDialog(R.string.progress_submit); + final QuestionDetail questionDetail = getData(); + OSChinaApi.getFavReverse(getDataId(), 2, new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + hideWaitDialog(); + if (questionDetail == null) + return; + if (questionDetail.isFavorite()) + AppContext.showToastShort(R.string.del_favorite_faile); + else + AppContext.showToastShort(R.string.add_favorite_faile); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + Type type = new TypeToken>() { + }.getType(); + + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, type); + if (resultBean != null && resultBean.isSuccess()) { + questionDetail.setFavorite(!questionDetail.isFavorite()); + mView.toFavoriteOk(questionDetail); + if (questionDetail.isFavorite()) + AppContext.showToastShort(R.string.add_favorite_success); + else + AppContext.showToastShort(R.string.del_favorite_success); + } + hideWaitDialog(); + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + } + }); + } + + @Override + public void toShare() { + if (getData() != null) { + final QuestionDetail detail = getData(); + String title = detail.getTitle(); + String content = detail.getBody(); + String url = detail.getHref(); + if (!toShare(title, content, url, 2)) + AppContext.showToast("抱歉,内容无法分享!"); + } else { + AppContext.showToast("内容加载失败!"); + } + } + + + @Override + public void toSendComment(long id, long commentId, long commentAuthorId, String comment) { + long uid = requestCheck(); + if (uid == 0) + return; + + if (TextUtils.isEmpty(comment)) { + AppContext.showToastShort(R.string.tip_comment_content_empty); + return; + } + + OSChinaApi.pubQuestionComment(id, commentId, commentAuthorId, comment, new TextHttpResponseHandler() { + + @Override + public void onStart() { + super.onStart(); + showWaitDialog(R.string.progress_submit); + } + + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + AppContext.showToast("评论失败!"); + hideWaitDialog(); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + Type type = new TypeToken>() { + }.getType(); + + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, type); + if (resultBean.isSuccess()) { + Comment respComment = resultBean.getResult(); + if (respComment != null) { + QuestionDetailContract.View view = mView; + if (view != null) { + view.toSendCommentOk(respComment); + } + } + } + hideWaitDialog(); + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + hideWaitDialog(); + } + }); + } + + @Override + public void toReport() { + long uid = requestCheck(); + if (uid == 0) + return; + toReport(getDataId(), getData().getHref(), Report.TYPE_QUESTION); + } + +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/activities/SchemeUrlActivity.java b/app/src/main/java/net/oschina/app/improve/detail/activities/SchemeUrlActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..7b60d1dd8732d3f1e01cb99d1fc31ed534be8318 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/activities/SchemeUrlActivity.java @@ -0,0 +1,77 @@ +package net.oschina.app.improve.detail.activities; + +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.Nullable; + +import net.oschina.app.R; +import net.oschina.app.improve.base.activities.BaseBackActivity; +import net.oschina.app.improve.main.MainActivity; +import net.oschina.app.improve.tweet.activities.TweetDetailActivity; +import net.oschina.app.improve.user.activities.OtherUserHomeActivity; +import net.oschina.app.util.TLog; +import net.oschina.app.util.UIHelper; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * web url 计划 activity + * Created by huanghaibin_dev + * on 2016/7/11. + */ + +public class SchemeUrlActivity extends BaseBackActivity { + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + try { + Intent intent = getIntent(); + if (intent != null) { + // oscapp://www.oschina.net/launch/app?type=-1(&id=112213) + String metaData = intent.getDataString(); + TLog.e("meta", metaData); + long id = 0; + int type = 0; + if (metaData != null) { + Pattern pattern = Pattern.compile("([^&?]*)"); + Matcher matcher = pattern.matcher(metaData); + while (matcher.find()) { + String group = matcher.group(); + if (!group.contains("www.oschina.net")) { + String[] param = group.split("="); + if (group.contains("type")) { + type = Integer.parseInt(param[1]); + } else if (group.contains("id")) { + id = Long.parseLong(param[1]); + } + } + } + + switch (type) { + case 20://打开个人中心 + OtherUserHomeActivity.show(this, id); + break; + case 100://打开动弹详情 + TweetDetailActivity.show(this, id); + break; + default: + if (id == 0)//默认启动首页 + startActivity(new Intent(this, MainActivity.class)); + else//否则启动各个类型详情 + UIHelper.showDetail(this, type, id, ""); + break; + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + finish(); + } + + @Override + protected int getContentView() { + return R.layout.activity_scheme_url; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/activities/SoftwareDetailActivity.java b/app/src/main/java/net/oschina/app/improve/detail/activities/SoftwareDetailActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..11dfbc0d7d0fda05d1c669de6258150a6c04764c --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/activities/SoftwareDetailActivity.java @@ -0,0 +1,156 @@ +package net.oschina.app.improve.detail.activities; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; + +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.AppContext; +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.bean.Collection; +import net.oschina.app.improve.bean.SoftwareDetail; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.detail.contract.SoftDetailContract; +import net.oschina.app.improve.detail.fragments.DetailFragment; +import net.oschina.app.improve.detail.fragments.SoftWareDetailFragment; +import net.oschina.app.util.TLog; + +import java.lang.reflect.Type; + +import cz.msebera.android.httpclient.Header; + +/** + * Created by fei on 2016/6/13. + * desc: news detail module + */ +public class SoftwareDetailActivity extends DetailActivity + implements SoftDetailContract.Operator { + + private String mIdent; + + @Override + int getOptionsMenuId() { + return 0; + } + + /** + * show news detail + * + * @param context context + * @param id id + */ + public static void show(Context context, long id) { + Intent intent = new Intent(context, SoftwareDetailActivity.class); + Bundle bundle = new Bundle(); + bundle.putLong("id", id); + intent.putExtras(bundle); + //intent.putExtra("id", id); + context.startActivity(intent); + } + + /** + * show news detail + * + * @param context context + * @param ident ident--> software Name + */ + public static void show(Context context, String ident) { + Intent intent = new Intent(context, SoftwareDetailActivity.class); + Bundle bundle = new Bundle(); + bundle.putString("ident", ident); + intent.putExtras(bundle); + context.startActivity(intent); + } + + @Override + protected boolean initBundle(Bundle bundle) { + mIdent = bundle.getString("ident", null); + return !TextUtils.isEmpty(mIdent) || super.initBundle(bundle); + } + + @Override + protected int getContentView() { + return R.layout.activity_blog_detail; + } + + @Override + void requestData() { + if (TextUtils.isEmpty(mIdent)) { + OSChinaApi.getNewsDetail(getDataId(), OSChinaApi.CATALOG_SOFTWARE_DETAIL, getRequestHandler()); + } else { + OSChinaApi.getSoftwareDetail(mIdent, OSChinaApi.CATALOG_SOFTWARE_DETAIL, getRequestHandler()); + } + } + + @Override + Class getDataViewFragment() { + return SoftWareDetailFragment.class; + } + + @Override + Type getDataType() { + return new TypeToken>() { + }.getType(); + } + + @Override + public void toFavorite() { + long uid = requestCheck(); + if (uid == 0) + return; + showWaitDialog(R.string.progress_submit); + final SoftwareDetail softwareDetail = getData(); + OSChinaApi.getFavReverse(getDataId(), 1, new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + hideWaitDialog(); + if (softwareDetail.isFavorite()) + AppContext.showToastShort(R.string.del_favorite_faile); + else + AppContext.showToastShort(R.string.add_favorite_faile); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + TLog.error(responseString); + try { + Type type = new TypeToken>() { + }.getType(); + + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, type); + if (resultBean != null && resultBean.isSuccess()) { + softwareDetail.setFavorite(!softwareDetail.isFavorite()); + mView.toFavoriteOk(softwareDetail); + if (softwareDetail.isFavorite()) + AppContext.showToastShort(R.string.add_favorite_success); + else + AppContext.showToastShort(R.string.del_favorite_success); + } + hideWaitDialog(); + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + } + }); + } + + @Override + public void toShare() { + if (getData() != null) { + final SoftwareDetail detail = getData(); + String title = detail.getName(); + String content = detail.getBody(); + String url = detail.getHref(); + if (!toShare(title, content, url, 1)) + AppContext.showToast("抱歉,内容无法分享!"); + } else { + AppContext.showToast("内容加载失败!"); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/activities/TranslateDetailActivity.java b/app/src/main/java/net/oschina/app/improve/detail/activities/TranslateDetailActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..f78d74a85d1db1f26d189b9d2ca0f6b52cf4d7bc --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/activities/TranslateDetailActivity.java @@ -0,0 +1,194 @@ +package net.oschina.app.improve.detail.activities; + +import android.content.Context; +import android.content.Intent; +import android.text.TextUtils; +import android.view.Menu; +import android.view.View; + +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.AppContext; +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.bean.Collection; +import net.oschina.app.improve.bean.TranslationDetail; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.bean.comment.Comment; +import net.oschina.app.improve.comment.CommentsActivity; +import net.oschina.app.improve.detail.contract.TranslateDetailContract; +import net.oschina.app.improve.detail.fragments.DetailFragment; +import net.oschina.app.improve.detail.fragments.TranslationDetailFragment; + +import java.lang.reflect.Type; + +import cz.msebera.android.httpclient.Header; + +/** + * Created by fei + * on 2016/6/13. + * desc: translate detail + */ +public class TranslateDetailActivity extends DetailActivity + implements TranslateDetailContract.Operator { + + /** + * show news detail + * + * @param context context + * @param id id + */ + public static void show(Context context, long id) { + Intent intent = new Intent(context, TranslateDetailActivity.class); + intent.putExtra("id", id); + context.startActivity(intent); + } + + int getType() { + return 4; + } + + @Override + protected int getContentView() { + return R.layout.activity_blog_detail; + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + boolean createOptionsMenu = super.onCreateOptionsMenu(menu); + if (createOptionsMenu) { + mCommentCountView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + CommentsActivity.show(TranslateDetailActivity.this, mDataId, OSChinaApi.COMMENT_TRANSLATION, OSChinaApi.COMMENT_NEW_ORDER); + } + }); + } + return createOptionsMenu; + } + + + @Override + void requestData() { + OSChinaApi.getNewsDetail(getDataId(), OSChinaApi.CATALOG_TRANSLATE_DETAIL, getRequestHandler()); + } + + @Override + Class getDataViewFragment() { + return TranslationDetailFragment.class; + } + + @Override + Type getDataType() { + return new TypeToken>() { + }.getType(); + } + + @Override + public void toFavorite() { + long uid = requestCheck(); + if (uid == 0) + return; + showWaitDialog(R.string.progress_submit); + final TranslationDetail translationDetail = getData(); + OSChinaApi.getFavReverse(getDataId(), getType(), new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + hideWaitDialog(); + if (translationDetail.isFavorite()) + AppContext.showToastShort(R.string.del_favorite_faile); + else + AppContext.showToastShort(R.string.add_favorite_faile); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + Type type = new TypeToken>() { + }.getType(); + + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, type); + if (resultBean != null && resultBean.isSuccess()) { + translationDetail.setFavorite(!translationDetail.isFavorite()); + mView.toFavoriteOk(translationDetail); + if (translationDetail.isFavorite()) + AppContext.showToastShort(R.string.add_favorite_success); + else + AppContext.showToastShort(R.string.del_favorite_success); + } + hideWaitDialog(); + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + } + }); + } + + @Override + public void toShare() { + if (getData() != null) { + final TranslationDetail detail = getData(); + String title = detail.getTitle(); + String content = detail.getBody(); + String url = detail.getHref(); + if (!toShare(title, content, url, 4)) + AppContext.showToast("抱歉,内容无法分享!"); + } else { + AppContext.showToast("内容加载失败!"); + } + } + + @Override + public void toSendComment(long id, long commentId, long commentAuthorId, String comment) { + long uid = requestCheck(); + if (uid == 0) + return; + + if (TextUtils.isEmpty(comment)) { + AppContext.showToastShort(R.string.tip_comment_content_empty); + return; + } + OSChinaApi.pubTranslateComment(id, commentId, commentAuthorId, comment, new TextHttpResponseHandler() { + + @Override + public void onStart() { + super.onStart(); + showWaitDialog(R.string.progress_submit); + } + + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + AppContext.showToast("评论失败!"); + hideWaitDialog(); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + Type type = new TypeToken>() { + }.getType(); + + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, type); + if (resultBean.isSuccess()) { + Comment respComment = resultBean.getResult(); + if (respComment != null) { + TranslateDetailContract.View view = mView; + if (view != null) { + view.toSendCommentOk(respComment); + } + } + } + hideWaitDialog(); + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + hideWaitDialog(); + } + }); + + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/contract/BlogDetailContract.java b/app/src/main/java/net/oschina/app/improve/detail/contract/BlogDetailContract.java new file mode 100644 index 0000000000000000000000000000000000000000..6765f2003d4313da52dec8a20468257d8108c392 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/contract/BlogDetailContract.java @@ -0,0 +1,37 @@ +package net.oschina.app.improve.detail.contract; + +import net.oschina.app.improve.bean.BlogDetail; +import net.oschina.app.improve.bean.comment.Comment; + +/** + * Created by qiujuer + * on 16/5/28. + */ + +public interface BlogDetailContract { + interface Operator extends DetailContract.Operator { + // 收藏 + void toFavorite(); + + // 分享 + void toShare(); + + // 关注 + void toFollow(); + + // 提交评价 + void toSendComment(long id, long commentId, long commentAuthorId, String comment); + +// void toReward(); + } + + interface View extends DetailContract.View { + void toFavoriteOk(BlogDetail blogDetail); + + void toFollowOk(BlogDetail blogDetail); + + void toSendCommentOk(Comment comment); + +// void toRewardOk(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/contract/DetailContract.java b/app/src/main/java/net/oschina/app/improve/detail/contract/DetailContract.java new file mode 100644 index 0000000000000000000000000000000000000000..b654fada9a6f7a279e9e7cdd2db6b70ddb456ccf --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/contract/DetailContract.java @@ -0,0 +1,28 @@ +package net.oschina.app.improve.detail.contract; + +/** + * Created by JuQiu + * on 16/6/20. + */ + +public interface DetailContract { + interface Operator { + // 获取当前数据 + Data getData(); + + void hideLoading(); + + // 回写布局View + void setDataView(DataView view); + + // 回写顶部评论数 + void setCommentCount(int count); + } + + interface View { + // 滚动到评论区域 + void scrollToComment(); + + } + +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/contract/EventDetailContract.java b/app/src/main/java/net/oschina/app/improve/detail/contract/EventDetailContract.java new file mode 100644 index 0000000000000000000000000000000000000000..98d7f5d94f493336b18c76c6493c581f0e19c90f --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/contract/EventDetailContract.java @@ -0,0 +1,22 @@ +package net.oschina.app.improve.detail.contract; + +import net.oschina.app.bean.EventApplyData; +import net.oschina.app.improve.bean.EventDetail; + +/** + * Created by huanghaibin + * on 16-6-13. + */ +public interface EventDetailContract { + interface View extends DetailContract.View { + void toFavOk(EventDetail detail); + + void toSignUpOk(EventDetail detail); + } + + interface Operator extends DetailContract.Operator { + void toFav(); + + void toSignUp(EventApplyData data); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/contract/NewsDetailContract.java b/app/src/main/java/net/oschina/app/improve/detail/contract/NewsDetailContract.java new file mode 100644 index 0000000000000000000000000000000000000000..3485410151bed9829453408c4ab2d645072d8366 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/contract/NewsDetailContract.java @@ -0,0 +1,28 @@ +package net.oschina.app.improve.detail.contract; + +import net.oschina.app.improve.bean.NewsDetail; +import net.oschina.app.improve.bean.comment.Comment; + +/** + * Created by fei on 2016/6/13. + * desc: + */ +public interface NewsDetailContract { + interface Operator extends DetailContract.Operator { + + // 收藏 + void toFavorite(); + + // 分享 + void toShare(); + + // 提交评价 + void toSendComment(long id, long commentId, long commentAuthorId, String comment); + } + + interface View extends DetailContract.View { + void toFavoriteOk(NewsDetail newsDetail); + + void toSendCommentOk(Comment comment); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/contract/QuestionDetailContract.java b/app/src/main/java/net/oschina/app/improve/detail/contract/QuestionDetailContract.java new file mode 100644 index 0000000000000000000000000000000000000000..3a2317ab7045e1589245f9f2425c2731f86b6358 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/contract/QuestionDetailContract.java @@ -0,0 +1,31 @@ +package net.oschina.app.improve.detail.contract; + +import net.oschina.app.improve.bean.QuestionDetail; +import net.oschina.app.improve.bean.comment.Comment; + +/** + * Created by fei on 2016/6/13. + * desc: + */ +public interface QuestionDetailContract { + interface Operator extends DetailContract.Operator { + + // 收藏 + void toFavorite(); + + // 分享 + void toShare(); + + // 举报 + void toReport(); + + // 提交评价 + void toSendComment(long id, long commentId, long commentAuthorId, String comment); + } + + interface View extends DetailContract.View { + void toFavoriteOk(QuestionDetail questionDetail); + + void toSendCommentOk(Comment comment); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/contract/SoftDetailContract.java b/app/src/main/java/net/oschina/app/improve/detail/contract/SoftDetailContract.java new file mode 100644 index 0000000000000000000000000000000000000000..eae544f9aa521db5d913bfa6ba55f933d215bcb5 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/contract/SoftDetailContract.java @@ -0,0 +1,24 @@ +package net.oschina.app.improve.detail.contract; + +import net.oschina.app.improve.bean.SoftwareDetail; + +/** + * Created by fei + * on 16/5/28. + * desc: + */ + +public interface SoftDetailContract { + interface Operator extends DetailContract.Operator { + + // 收藏 + void toFavorite(); + + // 分享 + void toShare(); + } + + interface View extends DetailContract.View { + void toFavoriteOk(SoftwareDetail softwareDetail); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/contract/TranslateDetailContract.java b/app/src/main/java/net/oschina/app/improve/detail/contract/TranslateDetailContract.java new file mode 100644 index 0000000000000000000000000000000000000000..ecd4c640c3f301eee3551940ca642903f225f373 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/contract/TranslateDetailContract.java @@ -0,0 +1,28 @@ +package net.oschina.app.improve.detail.contract; + +import net.oschina.app.improve.bean.TranslationDetail; +import net.oschina.app.improve.bean.comment.Comment; + +/** + * Created by fei on 2016/6/28. + * desc: + */ +public interface TranslateDetailContract { + interface Operator extends DetailContract.Operator { + + // 收藏 + void toFavorite(); + + // 分享 + void toShare(); + + // 提交评价 + void toSendComment(long id, long commentId, long commentAuthorId, String comment); + } + + interface View extends DetailContract.View { + void toFavoriteOk(TranslationDetail translationDetail); + + void toSendCommentOk(Comment comment); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/fragments/BlogDetailFragment.java b/app/src/main/java/net/oschina/app/improve/detail/fragments/BlogDetailFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..5e5a7134050d9ba9c86e76a249df3a2d6eea9ad5 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/fragments/BlogDetailFragment.java @@ -0,0 +1,372 @@ +package net.oschina.app.improve.detail.fragments; + +import android.app.Dialog; +import android.content.Intent; +import android.os.Build; +import android.support.design.widget.CoordinatorLayout; +import android.support.v4.widget.NestedScrollView; +import android.support.v7.app.AppCompatActivity; +import android.text.TextUtils; +import android.util.Log; +import android.view.KeyEvent; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.account.activity.LoginActivity; +import net.oschina.app.improve.bean.BlogDetail; +import net.oschina.app.improve.bean.User; +import net.oschina.app.improve.bean.comment.Comment; +import net.oschina.app.improve.bean.simple.About; +import net.oschina.app.improve.behavior.CommentBar; +import net.oschina.app.improve.comment.OnCommentClickListener; +import net.oschina.app.improve.detail.contract.BlogDetailContract; +import net.oschina.app.improve.pay.bean.Order; +import net.oschina.app.improve.pay.dialog.RewardDialog; +import net.oschina.app.improve.pay.util.RewardUtil; +import net.oschina.app.improve.tweet.service.TweetPublishService; +import net.oschina.app.improve.user.activities.OtherUserHomeActivity; +import net.oschina.app.improve.utils.DialogHelper; +import net.oschina.app.improve.widget.DetailAboutView; +import net.oschina.app.ui.SelectFriendsActivity; +import net.oschina.app.util.StringUtils; +import net.oschina.app.util.TLog; + +import java.net.URLEncoder; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import butterknife.Bind; +import butterknife.OnClick; +import cz.msebera.android.httpclient.Header; + + +/** + * Created by qiujuer + * on 16/5/26. + * Change by fei + * on 16/11/17 + * desc:blog detail + */ + +@SuppressWarnings("WeakerAccess") +public class BlogDetailFragment + extends DetailFragment + implements BlogDetailContract.View, View.OnClickListener, OnCommentClickListener { + + private long mId; + private long mCommentId; + private long mCommentAuthorId; + + @Bind(R.id.tv_name) + TextView mTVAuthorName; + @Bind(R.id.tv_pub_date) + TextView mTVPubDate; + @Bind(R.id.tv_title) + TextView mTVTitle; + + @Bind(R.id.tv_blog_detail_abstract) + TextView mTVAbstract; + @Bind(R.id.iv_label_recommend) + ImageView mIVLabelRecommend; + @Bind(R.id.iv_label_originate) + ImageView mIVLabelOriginate; + @Bind(R.id.iv_avatar) + ImageView mIVAuthorPortrait; + + @Bind(R.id.btn_relation) + Button mBtnRelation; + + @Bind(R.id.lay_detail_about) + DetailAboutView mAbouts; + + @Bind(R.id.lay_blog_detail_abstract) + LinearLayout mLayAbstract; + + @Bind(R.id.fragment_blog_detail) + CoordinatorLayout mLayCoordinator; + @Bind(R.id.lay_nsv) + NestedScrollView mLayContent; + + private Dialog mWaitDialog; + + private CommentBar mDelegation; + + @Override + protected int getLayoutId() { + return R.layout.fragment_general_blog_detail; + } + + @Override + protected void initWidget(View root) { + super.initWidget(root); + + mAbouts.setTitle(getString(R.string.label_about_title)); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + mBtnRelation.setElevation(0); + } + + mDelegation = CommentBar.delegation(getActivity(), mLayCoordinator); + + mDelegation.getBottomSheet().setCommitListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + handleSendComment(); + } + }); + + mDelegation.getBottomSheet().getEditText().setOnKeyListener(new View.OnKeyListener() { + @Override + public boolean onKey(View v, int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_DEL) { + handleKeyDel(); + } + return false; + } + }); + + mDelegation.setFavListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + handleFavorite(); + } + }); + mDelegation.setShareListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + handleShare(); + } + }); + + mDelegation.getBottomSheet().setMentionListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (AccountHelper.isLogin()) + SelectFriendsActivity.show(BlogDetailFragment.this); + else + LoginActivity.show(getActivity()); + } + }); + + } + + @OnClick({R.id.btn_relation, R.id.iv_avatar, R.id.btn_reward}) + @Override + public void onClick(View v) { + switch (v.getId()) { + // 关注按钮 + case R.id.btn_relation: + handleRelation(); + break; + case R.id.iv_avatar: + OtherUserHomeActivity.show(getActivity(), mOperator.getData().getAuthorId()); + break; + case R.id.btn_reward: + handleReward(); + default: + break; + + } + } + + + @SuppressWarnings("deprecation") + @Override + protected void initData() { + super.initData(); + BlogDetail blog = mOperator.getData(); + if (blog == null) + return; + + mId = mCommentId = blog.getId(); + + setCommentCount(blog.getCommentCount()); + setBodyContent(blog.getBody()); + + mTVAuthorName.setText(blog.getAuthor()); + getImgLoader().load(blog.getAuthorPortrait()).error(R.mipmap.widget_dface).into(mIVAuthorPortrait); + mIVAuthorPortrait.setOnClickListener(this); + + + mTVPubDate.setText(StringUtils.formatSomeAgo(blog.getPubDate())); + + mTVTitle.setText(blog.getTitle()); + + if (TextUtils.isEmpty(blog.getAbstract())) { + mLayAbstract.setVisibility(View.GONE); + } else { + mTVAbstract.setText(blog.getAbstract()); + mLayAbstract.setVisibility(View.VISIBLE); + } + + mIVLabelRecommend.setVisibility(blog.isRecommend() ? View.VISIBLE : View.GONE); + mIVLabelOriginate.setImageDrawable(blog.isOriginal() ? + getResources().getDrawable(R.mipmap.ic_label_originate) : + getResources().getDrawable(R.mipmap.ic_label_reprint)); + + toFollowOk(blog); + toFavoriteOk(blog); + + setText(R.id.tv_info_view, String.valueOf(blog.getViewCount())); + setText(R.id.tv_info_comment, String.valueOf(blog.getCommentCount())); + + mAbouts.setAbout(blog.getAbouts(), 3); + } + + private boolean mInputDoubleEmpty = false; + + private void handleKeyDel() { + if (mCommentId != mId) { + if (TextUtils.isEmpty(mDelegation.getBottomSheet().getCommentText())) { + if (mInputDoubleEmpty) { + mCommentId = mId; + mCommentAuthorId = 0; + mDelegation.setCommentHint(getString(R.string.pub_comment_hint)); + mDelegation.getBottomSheet().getEditText().setHint(getString(R.string.pub_comment_hint)); + } else { + mInputDoubleEmpty = true; + } + } else { + mInputDoubleEmpty = false; + } + } + } + + private void handleRelation() { + mOperator.toFollow(); + } + + private void handleFavorite() { + mOperator.toFavorite(); + } + + private void handleShare() { + mOperator.toShare(); + } + + private void handleSendComment() { + mOperator.toSendComment(mId, mCommentId, mCommentAuthorId, mDelegation.getBottomSheet().getCommentText()); + } + + private void handleReward() { + final BlogDetail detail = mOperator.getData(); + + final RewardDialog dialog = new RewardDialog(getContext()); + dialog.setCancelable(true); + dialog.setPortrait(detail.getAuthorPortrait()); + dialog.setNick(detail.getAuthor()); + dialog.setOnClickRewardListener(new RewardDialog.OnClickRewardCallback() { + @SuppressWarnings("deprecation") + @Override + public void reward(float cast) { + User user = AccountHelper.getUser(); + if (user == null || user.getId() <= 0) { + Toast.makeText(getContext(), "请先登录", Toast.LENGTH_SHORT).show(); + return; + } + + Map pairs = new ConcurrentHashMap<>(); + pairs.put("objType", "16344358"); + pairs.put("objId", String.valueOf(detail.getId())); + pairs.put("attach", Order.TYPE_ALIPAY); + pairs.put("money", String.valueOf((int) (cast * 100))); + pairs.put("subject", detail.getTitle()); + pairs.put("donater", String.valueOf(user.getId())); + pairs.put("author", String.valueOf(detail.getAuthorId())); + pairs.put("message", "Hello"); + pairs.put("returnUrl", URLEncoder.encode(detail.getHref())); + pairs.put("notifyUrl", URLEncoder.encode(detail.getNotifyUrl())); + + String sign = RewardUtil.sign(pairs); + pairs.put("sign", sign); + + mWaitDialog = DialogHelper.getProgressDialog(getContext(), "正在提交数据", false); + mWaitDialog.setCancelable(false); + + OSChinaApi.reward(pairs, new TextHttpResponseHandler() { + @Override + public void onSuccess(int statusCode, Header[] headers, String responseBody) { + TLog.e("oschina", "response body: " + responseBody); + } + + @Override + public void onFailure(int statusCode, Header[] headers, String responseBody, Throwable error) { + Log.e("oschina", "onFailure"); + //error.toString(); + + } + + @Override + public void onFinish() { + super.onFinish(); + dialog.dismiss(); + } + }); + } + }); + dialog.show(); + } + + @SuppressWarnings("deprecation") + @Override + public void toFavoriteOk(BlogDetail blogDetail) { + if (blogDetail.isFavorite()) + mDelegation.setFavDrawable(R.drawable.ic_faved); + else + mDelegation.setFavDrawable(R.drawable.ic_fav); + } + + @Override + public void toFollowOk(BlogDetail blogDetail) { + if (blogDetail.getAuthorRelation() <= 2) { + mBtnRelation.setText(getString(R.string.follow_done)); + } else { + mBtnRelation.setText(getString(R.string.following)); + } + } + + @Override + public void toSendCommentOk(Comment comment) { + if (mDelegation.getBottomSheet().isSyncToTweet()) { + BlogDetail detail = mOperator.getData(); + if (detail == null) return; + TweetPublishService.startActionPublish(getActivity(), + mDelegation.getBottomSheet().getCommentText(), null, + About.buildShare(detail.getId(), OSChinaApi.COMMENT_BLOG)); + } + Toast.makeText(getContext(), getResources().getString(R.string.pub_comment_success), Toast.LENGTH_SHORT).show(); + mDelegation.setCommentHint(getResources().getString(R.string.add_comment_hint)); + mDelegation.getBottomSheet().getEditText().setText(""); + mDelegation.getBottomSheet().getEditText().setHint(getResources().getString(R.string.add_comment_hint)); + // mComments.addComment(comment, getImgLoader(), this); + mDelegation.getBottomSheet().dismiss(); + } + + @Override + public void onClick(View view, Comment comment) { + mCommentId = comment.getId(); + mCommentAuthorId = comment.getAuthor().getId(); + mDelegation.setCommentHint(String.format("%s %s", getResources().getString(R.string.reply_hint), comment.getAuthor().getName())); + mDelegation.getBottomSheet().show(String.format("%s %s", getResources().getString(R.string.reply_hint), comment.getAuthor().getName())); + + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode == AppCompatActivity.RESULT_OK && data != null) { + mDelegation.getBottomSheet().handleSelectFriendsResult(data); + mDelegation.setCommentHint(mDelegation.getBottomSheet().getEditText().getHint().toString()); + } + } + +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/fragments/DetailFragment.java b/app/src/main/java/net/oschina/app/improve/detail/fragments/DetailFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..01fea3c7651c9957070f201378d190003c9b3e43 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/fragments/DetailFragment.java @@ -0,0 +1,158 @@ +package net.oschina.app.improve.detail.fragments; + +import android.content.Context; +import android.support.annotation.IdRes; +import android.support.v4.widget.NestedScrollView; +import android.view.View; +import android.view.ViewGroup; + +import net.oschina.app.R; +import net.oschina.app.improve.base.fragments.BaseFragment; +import net.oschina.app.improve.detail.contract.DetailContract; +import net.oschina.app.improve.widget.OWebView; + +/** + * Created by JuQiu + * on 16/6/20. + */ + +public abstract class DetailFragment> extends BaseFragment implements DetailContract.View { + Operator mOperator; + OWebView mWebView; + private NestedScrollView mScrollView; + private View mScrollTargetView; + + public Operator getOperator() { + return mOperator; + } + + @SuppressWarnings("unchecked") + @Override + public void onAttach(Context context) { + this.mOperator = (Operator) context; + this.mOperator.setDataView((DataView) this); + super.onAttach(context); + } + + @Override + protected void initWidget(View root) { + super.initWidget(root); + initWebView(R.id.lay_webview); + } + + void initWebView(@IdRes int layId) { + OWebView webView = new OWebView(getActivity()); + ((ViewGroup) mRoot.findViewById(layId)).addView(webView); + mWebView = webView; + } + + void setBodyContent(String body) { + mWebView.loadDetailDataAsync(body, new Runnable() { + @Override + public void run() { + Operator operator = mOperator; + if (operator != null) { + operator.hideLoading(); + } + } + }); + } + + void setCommentCount(int count) { + if (mOperator != null) { + mOperator.setCommentCount(count); + } + } + + void registerScroller(NestedScrollView nestedScrollView, View target) { + mScrollView = nestedScrollView; + mScrollTargetView = target; + } + + private int mScrollYPoint = -1; + + @Override + public void scrollToComment() { + NestedScrollView nestedScrollView = mScrollView; + View target = mScrollTargetView; + if (nestedScrollView != null && target != null) { + int curY = nestedScrollView.getScrollY(); + int targetY = target.getTop(); + if (targetY > 0) { + if (curY == targetY && targetY == mScrollYPoint) { + nestedScrollView.fullScroll(View.FOCUS_UP); + } else { + if (mScrollYPoint == -1) { + nestedScrollView.smoothScrollTo(0, targetY); + mScrollYPoint = curY; + return; + } + if (curY > targetY) { + // 当前在评论之后 + if (mScrollYPoint < targetY) { + nestedScrollView.smoothScrollTo(0, mScrollYPoint); + } else { + nestedScrollView.fullScroll(View.FOCUS_UP); + } + mScrollYPoint = curY; + } else { + // 当前在评论之前 + nestedScrollView.smoothScrollTo(0, mScrollYPoint); + if (mScrollYPoint < curY) { + mScrollYPoint = -1; + } else { + mScrollYPoint = 0; + } + } + } + } else { + if (mScrollYPoint == -1) { + nestedScrollView.fullScroll(View.FOCUS_DOWN); + mScrollYPoint = curY; + } else { + nestedScrollView.smoothScrollTo(0, mScrollYPoint); + mScrollYPoint = -1; + } + } + } + } + + + @Override + public void onResume() { + super.onResume(); + OWebView webView = mWebView; + if (webView != null) { + webView.onResume(); + } + } + + @Override + public void onPause() { + super.onPause(); + OWebView webView = mWebView; + if (webView != null) { + webView.onPause(); + } + } + + @Override + public void onDestroy() { + OWebView view = mWebView; + if (view != null) { + mWebView = null; + view.destroy(); + } + + mScrollTargetView = null; + NestedScrollView nestedScrollView = mScrollView; + if (nestedScrollView != null) { + mScrollView = null; + nestedScrollView.setOnScrollChangeListener((NestedScrollView.OnScrollChangeListener) null); + } + + mOperator = null; + + super.onDestroy(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/fragments/EventDetailFragment.java b/app/src/main/java/net/oschina/app/improve/detail/fragments/EventDetailFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..b6227a0090e5db69284c69e71da75cd54ce748cd --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/fragments/EventDetailFragment.java @@ -0,0 +1,230 @@ +package net.oschina.app.improve.detail.fragments; + +import android.app.Activity; +import android.content.Intent; +import android.view.View; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.account.activity.LoginActivity; +import net.oschina.app.improve.bean.Event; +import net.oschina.app.improve.bean.EventDetail; +import net.oschina.app.improve.comment.CommentsActivity; +import net.oschina.app.improve.detail.contract.EventDetailContract; +import net.oschina.app.improve.detail.sign.SignUpActivity; +import net.oschina.app.improve.dialog.EventDetailApplyDialog; + +import butterknife.Bind; +import butterknife.OnClick; + +/** + * Created by huanghaibin + * on 16-6-13. + */ +@SuppressWarnings("WeakerAccess") +public class EventDetailFragment extends DetailFragment implements + View.OnClickListener, EventDetailContract.View { + + @Bind(R.id.ll_sign) + LinearLayout ll_sign; + + @Bind(R.id.iv_event_img) + ImageView iv_event_img; + + @Bind(R.id.iv_fav) + ImageView iv_fav; + + @Bind(R.id.iv_sign) + ImageView iv_sign; + + @Bind(R.id.tv_event_title) + TextView tv_event_title; + + @Bind(R.id.tv_event_author) + TextView tv_event_author; + + @Bind(R.id.tv_event_type) + TextView tv_event_type; + + @Bind(R.id.tv_event_cost_desc) + TextView tv_event_cost_desc; + + @Bind(R.id.tv_event_member) + TextView tv_event_member; + + @Bind(R.id.tv_event_status) + TextView tv_event_status; + + @Bind(R.id.tv_event_start_date) + TextView tv_event_start_date; + + @Bind(R.id.tv_event_location) + TextView tv_event_location; + + @Bind(R.id.tv_fav) + TextView tv_fav; + + @Bind(R.id.tv_apply_status) + TextView tv_apply_status; + + @Bind(R.id.tv_comment) + TextView tv_comment; + + private EventDetailApplyDialog mEventApplyDialog; + + @Override + protected int getLayoutId() { + return R.layout.fragment_improve_event_detail; + } + + + @Override + protected void initData() { + final EventDetail mDetail = mOperator.getData(); + if (mDetail == null) return; + tv_comment.setText(String.format("评论(%s)", mDetail.getCommentCount())); + tv_event_title.setText(mDetail.getTitle()); + tv_event_author.setText(String.format("发起人:%s", mDetail.getAuthor())); + tv_event_member.setText(String.format("%s人参与", mDetail.getApplyCount())); + tv_event_cost_desc.setText(mDetail.getCostDesc()); + tv_event_location.setText(mDetail.getSpot()); + tv_event_start_date.setText(mDetail.getStartDate()); + getImgLoader().load(mDetail.getImg()).into(iv_event_img); + iv_fav.setImageResource(mDetail.isFavorite() ? R.drawable.ic_faved : R.drawable.ic_fav); + tv_fav.setText(mDetail.isFavorite() ? getResources().getString(R.string.event_is_fav) : getResources().getString(R.string.event_un_fav)); + switch (mDetail.getStatus()) { + case Event.STATUS_END: + tv_event_status.setText(getResources().getString(R.string.event_status_end)); + break; + case Event.STATUS_ING: + tv_event_status.setText(getResources().getString(R.string.event_status_ing)); + break; + case Event.STATUS_SING_UP: + tv_event_status.setText(getResources().getString(R.string.event_status_sing_up)); + break; + } + int typeStr = R.string.oscsite; + switch (mDetail.getType()) { + case Event.EVENT_TYPE_OSC: + typeStr = R.string.event_type_osc; + break; + case Event.EVENT_TYPE_TEC: + typeStr = R.string.event_type_tec; + break; + case Event.EVENT_TYPE_OTHER: + typeStr = R.string.event_type_other; + break; + case Event.EVENT_TYPE_OUTSIDE: + typeStr = R.string.event_type_outside; + break; + } + tv_event_type.setText(String.format("类型:%s", getResources().getString(typeStr))); + tv_apply_status.setText(getResources().getString(getApplyStatusStrId(mDetail.getApplyStatus()))); + + if (mDetail.getStatus() != EventDetail.STATUS_ING || + mDetail.getApplyStatus() != EventDetail.APPLY_STATUS_UN_SIGN) { + setSignUnEnable(); + } + setBodyContent(mDetail.getBody()); + } + + @OnClick({R.id.ll_fav, R.id.ll_sign, R.id.ll_comment}) + @Override + public void onClick(View v) { + + switch (v.getId()) { + case R.id.ll_fav: + if (!AccountHelper.isLogin()) { + LoginActivity.show(EventDetailFragment.this, 1); + return; + } + mOperator.toFav(); + break; + case R.id.ll_sign: + if (!AccountHelper.isLogin()) { + LoginActivity.show(getActivity(), 0x02); + return; + } + SignUpActivity.show(this, mOperator.getData().getId()); + break; + case R.id.ll_comment: + CommentsActivity.show(getActivity(), mOperator.getData().getId(), OSChinaApi.COMMENT_EVENT, OSChinaApi.COMMENT_NEW_ORDER); + break; + } + } + + /** + * 添加收藏成功 + * + * @param detail detail + */ + @Override + public void toFavOk(EventDetail detail) { + mOperator.getData().setFavorite(detail.isFavorite()); + final EventDetail mDetail = mOperator.getData(); + iv_fav.setImageResource(mDetail.isFavorite() ? R.drawable.ic_faved : R.drawable.ic_fav); + tv_fav.setText(mDetail.isFavorite() ? getResources().getString(R.string.event_is_fav) : getResources().getString(R.string.event_un_fav)); + } + + /** + * 报名成功 + * + * @param detail detail + */ + @Override + public void toSignUpOk(EventDetail detail) { + mOperator.getData().setApplyStatus(detail.getApplyStatus()); + final EventDetail mDetail = mOperator.getData(); + tv_apply_status.setText(getResources().getString(getApplyStatusStrId(mDetail.getApplyStatus()))); + setSignUnEnable(); + mEventApplyDialog.dismiss(); + } + + public int getApplyStatusStrId(int status) { + int strId = R.string.event_status_ing; + switch (status) { + case EventDetail.APPLY_STATUS_UN_SIGN: + strId = R.string.event_apply_status_un_sign; + break; + case EventDetail.APPLY_STATUS_AUDIT: + strId = R.string.event_apply_status_audit; + break; + case EventDetail.APPLY_STATUS_CONFIRMED: + strId = R.string.event_apply_status_confirmed; + break; + case EventDetail.APPLY_STATUS_PRESENTED: + strId = R.string.event_apply_status_presented; + break; + case EventDetail.APPLY_STATUS_CANCELED: + strId = R.string.event_apply_status_canceled; + break; + case EventDetail.APPLY_STATUS_REFUSED: + strId = R.string.event_apply_status_refused; + break; + } + return strId; + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode == Activity.RESULT_OK && data != null) { + switch (requestCode) { + case 0x01: + tv_apply_status.setText(getResources().getString(getApplyStatusStrId(EventDetail.APPLY_STATUS_AUDIT))); + setSignUnEnable(); + break; + } + } + } + + private void setSignUnEnable() { + tv_apply_status.setEnabled(false); + ll_sign.setEnabled(false); + iv_sign.setEnabled(false); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/fragments/NewsDetailFragment.java b/app/src/main/java/net/oschina/app/improve/detail/fragments/NewsDetailFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..03c18d52b7892430131263137148a9ccf4f73033 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/fragments/NewsDetailFragment.java @@ -0,0 +1,270 @@ +package net.oschina.app.improve.detail.fragments; + +import android.content.Intent; +import android.support.design.widget.CoordinatorLayout; +import android.support.v7.app.AppCompatActivity; +import android.text.TextUtils; +import android.view.KeyEvent; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.account.activity.LoginActivity; +import net.oschina.app.improve.bean.NewsDetail; +import net.oschina.app.improve.bean.Software; +import net.oschina.app.improve.bean.comment.Comment; +import net.oschina.app.improve.bean.simple.About; +import net.oschina.app.improve.behavior.CommentBar; +import net.oschina.app.improve.comment.CommentView; +import net.oschina.app.improve.comment.OnCommentClickListener; +import net.oschina.app.improve.detail.activities.SoftwareDetailActivity; +import net.oschina.app.improve.detail.contract.NewsDetailContract; +import net.oschina.app.improve.tweet.service.TweetPublishService; +import net.oschina.app.improve.user.activities.OtherUserHomeActivity; +import net.oschina.app.improve.widget.DetailAboutView; +import net.oschina.app.ui.SelectFriendsActivity; +import net.oschina.app.util.StringUtils; +import net.oschina.app.util.TDevice; + +/** + * Created by fei + * on 16/5/26. + * change by fei + * on 16/11/17 + * desc: news detail + */ + +public class NewsDetailFragment extends DetailFragment + implements View.OnClickListener, NewsDetailContract.View, OnCommentClickListener { + + private long mId; + // private TextView mTVAuthorName; + private TextView mTVPubDate; + private TextView mTVTitle; + // private ImageView mIVAuthorPortrait; + + private long mCommentId; + private long mCommentAuthorId; + private boolean mInputDoubleEmpty = false; + private DetailAboutView mAbouts; + private CommentView mComment; + private TextView mAboutSoftwareTitle; + private LinearLayout mAboutSoftware; + private TextView mTVName; + + private CommentBar mDelegation; + + @Override + protected int getLayoutId() { + return R.layout.fragment_general_news_detail; + } + + + @Override + protected void initWidget(View root) { + super.initWidget(root); + + //mTVAuthorName = (TextView) root.findViewById(R.id.tv_name); + mTVPubDate = (TextView) root.findViewById(R.id.tv_pub_date); + mTVTitle = (TextView) root.findViewById(R.id.tv_title); + mTVName = (TextView) root.findViewById(R.id.tv_info_view); + mTVName.setOnClickListener(this); + + setGone(R.id.iv_info_view); + //setGone(R.id.tv_info_view); + setGone(R.id.iv_info_comment); + + mAbouts = (DetailAboutView) root.findViewById(R.id.lay_detail_about); + mAboutSoftware = (LinearLayout) root.findViewById(R.id.lay_about_software); + mAboutSoftwareTitle = (TextView) root.findViewById(R.id.tv_about_software_title); + mComment = (CommentView) root.findViewById(R.id.lay_detail_comment); + + CoordinatorLayout mLayCoordinator = (CoordinatorLayout) root.findViewById(R.id.fragment_blog_detail); + //NestedScrollView mLayContent = (NestedScrollView) root.findViewById(R.id.lay_nsv); + + //registerScroller(mLayContent, mComment); + + mDelegation = CommentBar.delegation(getActivity(), mLayCoordinator); + + mDelegation.getBottomSheet().getEditText().setOnKeyListener(new View.OnKeyListener() { + @Override + public boolean onKey(View v, int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_DEL) { + handleKeyDel(); + } + return false; + } + }); + + mDelegation.setFavListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + handleFavorite(); + } + }); + mDelegation.setShareListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + handleShare(); + } + }); + mDelegation.getBottomSheet().setFaceListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + TDevice.showSoftKeyboard(mDelegation.getBottomSheet().getEditText()); + } + }); + + mDelegation.getBottomSheet().setCommitListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + handleSendComment(); + } + }); + + mDelegation.getBottomSheet().setMentionListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (AccountHelper.isLogin()) + SelectFriendsActivity.show(NewsDetailFragment.this); + else + LoginActivity.show(getActivity()); + } + }); + + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + // 相关软件 + case R.id.lay_about_software: + SoftwareDetailActivity.show(getActivity(), mOperator.getData().getSoftware().getId()); + break; + case R.id.tv_info_view: + OtherUserHomeActivity.show(getActivity(), mOperator.getData().getAuthorId()); + break; + default: + break; + } + } + + @Override + protected void initData() { + final NewsDetail newsDetail = mOperator.getData(); + if (newsDetail == null) + return; + + mId = mCommentId = newsDetail.getId(); + + setCommentCount(newsDetail.getCommentCount()); + setBodyContent(newsDetail.getBody()); + + mTVName.setText(String.format("%s%s%s%s", "@", newsDetail.getAuthor(), " ", getResources().getString(R.string.pub_about) + " ")); + + mTVPubDate.setText(StringUtils.formatSomeAgo(newsDetail.getPubDate())); + + mTVTitle.setText(newsDetail.getTitle()); + + toFavoriteOk(newsDetail); + + setText(R.id.tv_info_comment, StringUtils.formatYearMonthDay(newsDetail.getPubDate())); + + Software software = newsDetail.getSoftware(); + if (software != null) { + mAboutSoftware.setOnClickListener(this); + mAboutSoftwareTitle.setText(software.getName()); + } else { + mAboutSoftware.setVisibility(View.GONE); + } + + mAbouts.setAbout(newsDetail.getAbouts(), 6); + + mComment.setTitle(String.format("%s", getResources().getString(R.string.hot_comment_hint))); + mComment.init(newsDetail.getId(), + OSChinaApi.COMMENT_NEWS, + OSChinaApi.COMMENT_HOT_ORDER, + newsDetail.getCommentCount(), + getImgLoader(), this); + } + + private void handleKeyDel() { + if (mCommentId != mId) { + if (TextUtils.isEmpty(mDelegation.getBottomSheet().getCommentText())) { + if (mInputDoubleEmpty) { + mCommentId = mId; + mCommentAuthorId = 0; + mDelegation.setCommentHint(getString(R.string.pub_comment_hint)); + mDelegation.getBottomSheet().getEditText().setHint(getString(R.string.pub_comment_hint)); + } else { + mInputDoubleEmpty = true; + } + } else { + mInputDoubleEmpty = false; + } + } + } + + + private void handleFavorite() { + mOperator.toFavorite(); + } + + private void handleShare() { + mOperator.toShare(); + } + + private void handleSendComment() { + mOperator.toSendComment(mId, mCommentId, mCommentAuthorId, mDelegation.getBottomSheet().getCommentText()); + } + + @SuppressWarnings("deprecation") + @Override + public void toFavoriteOk(NewsDetail newsDetail) { + if (newsDetail.isFavorite()) + mDelegation.setFavDrawable(R.drawable.ic_faved); + else + mDelegation.setFavDrawable(R.drawable.ic_fav); + } + + @Override + public void toSendCommentOk(final Comment comment) { + if (mDelegation.getBottomSheet().isSyncToTweet()) { + NewsDetail detail = mOperator.getData(); + if (detail == null) return; + TweetPublishService.startActionPublish(getActivity(), + mDelegation.getBottomSheet().getCommentText(), null, + About.buildShare(detail.getId(), OSChinaApi.COMMENT_NEWS)); + } + Toast.makeText(getContext(), getString(R.string.pub_comment_success), Toast.LENGTH_SHORT).show(); + mDelegation.getCommentText().setHint(getString(R.string.add_comment_hint)); + mDelegation.getBottomSheet().getEditText().setText(""); + mDelegation.getBottomSheet().getEditText().setHint(getString(R.string.add_comment_hint)); + mDelegation.getBottomSheet().dismiss(); + } + + @Override + public void onClick(View view, Comment comment) { + mCommentId = comment.getId(); + + mCommentAuthorId = comment.getAuthor().getId(); + mDelegation.getCommentText().setHint(String.format("%s %s", getResources().getString(R.string.reply_hint), comment.getAuthor().getName())); + + mDelegation.getBottomSheet().show(String.format("%s %s", getResources().getString(R.string.reply_hint), comment.getAuthor().getName())); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode == AppCompatActivity.RESULT_OK && data != null) { + mDelegation.getBottomSheet().handleSelectFriendsResult(data); + mDelegation.setCommentHint(mDelegation.getBottomSheet().getEditText().getHint().toString()); + } + } + +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/fragments/QuestionDetailFragment.java b/app/src/main/java/net/oschina/app/improve/detail/fragments/QuestionDetailFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..0086e4e74c4db23e309a9ed7a05eb36d242bd1a4 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/fragments/QuestionDetailFragment.java @@ -0,0 +1,252 @@ +package net.oschina.app.improve.detail.fragments; + +import android.annotation.SuppressLint; +import android.content.Intent; +import android.support.design.widget.CoordinatorLayout; +import android.support.v4.widget.NestedScrollView; +import android.support.v7.app.AppCompatActivity; +import android.text.TextUtils; +import android.view.KeyEvent; +import android.view.View; +import android.widget.TextView; +import android.widget.Toast; + +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.account.activity.LoginActivity; +import net.oschina.app.improve.bean.QuestionDetail; +import net.oschina.app.improve.bean.comment.Comment; +import net.oschina.app.improve.bean.simple.About; +import net.oschina.app.improve.behavior.CommentBar; +import net.oschina.app.improve.comment.CommentView; +import net.oschina.app.improve.comment.OnCommentClickListener; +import net.oschina.app.improve.detail.contract.QuestionDetailContract; +import net.oschina.app.improve.tweet.service.TweetPublishService; +import net.oschina.app.improve.widget.FlowLayout; +import net.oschina.app.ui.SelectFriendsActivity; +import net.oschina.app.util.StringUtils; + +import java.util.List; + +/** + * Created by fei + * on 16/5/26. + * desc: + */ + +public class QuestionDetailFragment extends DetailFragment + implements QuestionDetailContract.View, OnCommentClickListener { + + private long mId; + private TextView mTVAuthorName; + private TextView mTVPubDate; + private TextView mTVTitle; + + private long mCommentId; + private long mCommentAuthorId; + private CommentView mComments; + + private FlowLayout mFlowLayout; + + private CommentBar mDelegation; + + @Override + protected int getLayoutId() { + return R.layout.fragment_general_question_detail; + } + + @Override + protected void initWidget(View root) { + super.initWidget(root); + + mTVAuthorName = (TextView) root.findViewById(R.id.tv_ques_detail_author); + mTVPubDate = (TextView) root.findViewById(R.id.tv_ques_detail_pub_date); + mTVTitle = (TextView) root.findViewById(R.id.tv_ques_detail_title); + + mFlowLayout = (FlowLayout) root.findViewById(R.id.ques_detail_flow); + + mComments = (CommentView) root.findViewById(R.id.lay_detail_comment); + CoordinatorLayout mLayCoordinator = (CoordinatorLayout) root.findViewById(R.id.activity_blog_detail); + NestedScrollView mLayContent = (NestedScrollView) root.findViewById(R.id.lay_nsv); + + registerScroller(mLayContent, mComments); + + mDelegation = CommentBar.delegation(getActivity(), mLayCoordinator); + + mDelegation.getBottomSheet().getEditText().setOnKeyListener(new View.OnKeyListener() { + @Override + public boolean onKey(View v, int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_DEL) { + handleKeyDel(); + } + return false; + } + }); + + mDelegation.setFavListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + handleFavorite(); + } + }); + mDelegation.setShareListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + handleShare(); + } + }); + mDelegation.getBottomSheet().setCommitListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + handleSendComment(); + } + }); + + mDelegation.getBottomSheet().getEditText().setOnKeyListener(new View.OnKeyListener() { + @Override + public boolean onKey(View v, int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_DEL) { + handleKeyDel(); + } + return false; + } + }); + + mDelegation.getBottomSheet().setMentionListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (AccountHelper.isLogin()) + SelectFriendsActivity.show(QuestionDetailFragment.this); + else + LoginActivity.show(getActivity()); + } + }); + } + + @SuppressLint("DefaultLocale") + @Override + protected void initData() { + + QuestionDetail questionDetail = mOperator.getData(); + if (questionDetail == null) + return; + + mId = mCommentId = questionDetail.getId(); + + String body = questionDetail.getBody(); + + setCommentCount(questionDetail.getCommentCount()); + setBodyContent(body); + + String author = questionDetail.getAuthor(); + if (!TextUtils.isEmpty(author)) + mTVAuthorName.setText(author); + + List tags = questionDetail.getTags(); + + // mFlowLayout.removeAllViews(); + if (tags != null && !tags.isEmpty()) { + for (String tag : tags) { + TextView tvTag = (TextView) getActivity().getLayoutInflater().inflate(R.layout.flowlayout_item, mFlowLayout, false); + if (!TextUtils.isEmpty(tag)) + tvTag.setText(tag); + mFlowLayout.addView(tvTag); + } + } + + mTVPubDate.setText(StringUtils.formatSomeAgo(questionDetail.getPubDate())); + + String title = questionDetail.getTitle(); + if (!TextUtils.isEmpty(title)) + mTVTitle.setText(title); + + toFavoriteOk(questionDetail); + + setText(R.id.tv_info_view, String.valueOf(questionDetail.getViewCount())); + setText(R.id.tv_info_comment, String.valueOf(questionDetail.getCommentCount())); + + mComments.setTitle(String.format("%s (%d)", getResources().getString(R.string.answer_hint), questionDetail.getCommentCount())); + mComments.setCommentBar(mDelegation); + mComments.init(questionDetail.getId(), + OSChinaApi.COMMENT_QUESTION, + OSChinaApi.COMMENT_NEW_ORDER, + questionDetail.getCommentCount(), + getImgLoader(), this); + } + + private boolean mInputDoubleEmpty = false; + + private void handleKeyDel() { + if (mCommentId != mId) { + if (TextUtils.isEmpty(mDelegation.getBottomSheet().getCommentText())) { + if (mInputDoubleEmpty) { + mCommentId = mId; + mCommentAuthorId = 0; + mDelegation.setCommentHint(getString(R.string.pub_comment_hint)); + mDelegation.getBottomSheet().getEditText().setHint(getString(R.string.pub_comment_hint)); + } else { + mInputDoubleEmpty = true; + } + } else { + mInputDoubleEmpty = false; + } + } + } + + + private void handleFavorite() { + mOperator.toFavorite(); + } + + private void handleShare() { + mOperator.toShare(); + } + + private void handleSendComment() { + mOperator.toSendComment(mId, mCommentId, mCommentAuthorId, mDelegation.getBottomSheet().getCommentText()); + } + + + @SuppressWarnings("deprecation") + @Override + public void toFavoriteOk(QuestionDetail questionDetail) { + if (questionDetail.isFavorite()) + mDelegation.setFavDrawable(R.drawable.ic_faved); + else + mDelegation.setFavDrawable(R.drawable.ic_fav); + } + + @Override + public void toSendCommentOk(Comment comment) { + if (mDelegation.getBottomSheet().isSyncToTweet()) { + QuestionDetail detail = mOperator.getData(); + if (detail == null) return; + TweetPublishService.startActionPublish(getActivity(), + mDelegation.getBottomSheet().getCommentText(), null, + About.buildShare(detail.getId(), OSChinaApi.COMMENT_QUESTION)); + } + mDelegation.setCommentHint(getResources().getString(R.string.add_comment_hint)); + mDelegation.getBottomSheet().getEditText().setText(""); + mDelegation.getBottomSheet().getEditText().setHint(getResources().getString(R.string.add_comment_hint)); + mDelegation.getBottomSheet().dismiss(); + Toast.makeText(getContext(), getResources().getString(R.string.pub_comment_success), Toast.LENGTH_LONG).show(); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode == AppCompatActivity.RESULT_OK && data != null) { + mDelegation.getBottomSheet().handleSelectFriendsResult(data); + mDelegation.setCommentHint(mDelegation.getBottomSheet().getEditText().getHint().toString()); + } + } + + @Override + public void onClick(View view, Comment comment) { + mCommentId = comment.getId(); + mCommentAuthorId = comment.getAuthor().getId(); + mDelegation.getCommentText().setHint(String.format("%s %s", getResources().getString(R.string.reply_hint), comment.getAuthor().getName())); + mDelegation.getBottomSheet().show(String.format("%s %s", getResources().getString(R.string.reply_hint), comment.getAuthor().getName())); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/fragments/SoftWareDetailFragment.java b/app/src/main/java/net/oschina/app/improve/detail/fragments/SoftWareDetailFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..5b1d830cd2dc583e84d59aa56d79060d70d5b92e --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/fragments/SoftWareDetailFragment.java @@ -0,0 +1,163 @@ +package net.oschina.app.improve.detail.fragments; + +import android.text.TextUtils; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import net.oschina.app.R; +import net.oschina.app.improve.bean.SoftwareDetail; +import net.oschina.app.improve.detail.contract.SoftDetailContract; +import net.oschina.app.improve.tweet.activities.SoftwareTweetActivity; +import net.oschina.app.improve.user.activities.OtherUserHomeActivity; +import net.oschina.app.improve.widget.DetailAboutView; +import net.oschina.app.util.UIHelper; + +import butterknife.Bind; +import butterknife.OnClick; + +/** + * Created by fei on 2016/6/20. + * desc: software detail module + */ +public class SoftWareDetailFragment extends DetailFragment + implements View.OnClickListener, SoftDetailContract.View { + + @Bind(R.id.iv_label_recommend) + ImageView ivRecomment; + + @Bind(R.id.iv_software_icon) + ImageView ivIcon; + @Bind(R.id.tv_software_name) + TextView tvName; + + @Bind(R.id.tv_software_author_name) + TextView tvAuthor; + @Bind(R.id.tv_software_law) + TextView tvLicense; + @Bind(R.id.tv_software_language) + TextView tvLanguage; + @Bind(R.id.tv_software_system) + TextView tvSystem; + @Bind(R.id.tv_software_record_time) + TextView tvRecordTime; + + @Bind(R.id.lay_detail_about) + DetailAboutView mAbouts; + + @Bind(R.id.lay_option_fav_text) + TextView mCommentText; + @Bind(R.id.lay_option_fav_icon) + ImageView mIVFav; + + @Override + protected int getLayoutId() { + return R.layout.fragment_general_soft_detail; + } + + @OnClick({R.id.lay_option_share, R.id.lay_option_fav, R.id.bt_software_home, R.id.bt_software_document, + R.id.lay_option_comment, R.id.tv_software_author_name}) + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.lay_option_share: + // 分享 + handleShare(); + break; + case R.id.lay_option_fav: + // 收藏 + handleFavorite(); + break; + case R.id.bt_software_home: + //进入官网 + UIHelper.showUrlRedirect(getActivity(), mOperator.getData().getHomePage()); + break; + case R.id.bt_software_document: + //软件文档 + UIHelper.showUrlRedirect(getActivity(), mOperator.getData().getDocument()); + break; + case R.id.lay_option_comment: + // 评论列表 + SoftwareDetail detail = mOperator.getData(); + String tag = detail.getIdentification(); + String name = detail.getName(); + if (TextUtils.isEmpty(tag)) + tag = name; + + SoftwareTweetActivity.show(getContext(), tag, name); + break; + case R.id.tv_software_author_name: + + long authorId = mOperator.getData().getAuthorId(); + String author = mOperator.getData().getAuthor(); + if (authorId <= 0 || TextUtils.isEmpty(author)) return; + + OtherUserHomeActivity.show(getActivity(), authorId); + + break; + default: + break; + } + } + + @SuppressWarnings("deprecation") + @Override + protected void initData() { + final SoftwareDetail softwareDetail = mOperator.getData(); + + if (softwareDetail == null) { + return; + } + + if (softwareDetail.isRecommend()) { + ivRecomment.setVisibility(View.VISIBLE); + } else { + ivRecomment.setVisibility(View.INVISIBLE); + } + + String name = softwareDetail.getName(); + String extName = softwareDetail.getExtName(); + tvName.setText(String.format("%s%s", TextUtils.isEmpty(name) ? "" : name, (TextUtils.isEmpty(extName)) ? "" : " " + extName.trim())); + + String author = softwareDetail.getAuthor(); + tvAuthor.setText(TextUtils.isEmpty(author) ? getString(R.string.soft_detail_any_name) : author.trim()); + String license = softwareDetail.getLicense(); + tvLicense.setText(TextUtils.isEmpty(license) ? getString(R.string.soft_detail_no_license) : license.trim()); + tvLanguage.setText(softwareDetail.getLanguage()); + tvSystem.setText(softwareDetail.getSupportOS()); + tvRecordTime.setText(softwareDetail.getCollectionDate()); + + setCommentCount(softwareDetail.getCommentCount()); + setBodyContent(softwareDetail.getBody()); + getImgLoader().load(softwareDetail.getLogo()) + .error(R.mipmap.logo_software_default) + .placeholder(R.mipmap.logo_software_default) + .into(ivIcon); + + toFavoriteOk(softwareDetail); + + mAbouts.setAbout(softwareDetail.getAbouts(), 1); + } + + @Override + void setCommentCount(int count) { + mCommentText.setText(String.format("%s (%s)", getString(R.string.comment_title_hint), count)); + } + + private void handleFavorite() { + mOperator.toFavorite(); + } + + private void handleShare() { + mOperator.toShare(); + } + + @SuppressWarnings("deprecation") + @Override + public void toFavoriteOk(SoftwareDetail softwareDetail) { + if (softwareDetail.isFavorite()) + mIVFav.setImageDrawable(getResources().getDrawable(R.drawable.ic_faved)); + else + mIVFav.setImageDrawable(getResources().getDrawable(R.drawable.ic_fav)); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/fragments/TranslationDetailFragment.java b/app/src/main/java/net/oschina/app/improve/detail/fragments/TranslationDetailFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..a8755f529f43873f8b16e279a02b0b5b4babf516 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/fragments/TranslationDetailFragment.java @@ -0,0 +1,239 @@ +package net.oschina.app.improve.detail.fragments; + +import android.content.Intent; +import android.support.design.widget.CoordinatorLayout; +import android.support.v4.widget.NestedScrollView; +import android.support.v7.app.AppCompatActivity; +import android.text.TextUtils; +import android.view.KeyEvent; +import android.view.View; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.account.activity.LoginActivity; +import net.oschina.app.improve.bean.TranslationDetail; +import net.oschina.app.improve.bean.comment.Comment; +import net.oschina.app.improve.bean.simple.About; +import net.oschina.app.improve.behavior.CommentBar; +import net.oschina.app.improve.behavior.FloatingAutoHideDownBehavior; +import net.oschina.app.improve.comment.CommentView; +import net.oschina.app.improve.comment.OnCommentClickListener; +import net.oschina.app.improve.detail.contract.TranslateDetailContract; +import net.oschina.app.improve.tweet.service.TweetPublishService; +import net.oschina.app.improve.widget.DetailAboutView; +import net.oschina.app.ui.SelectFriendsActivity; +import net.oschina.app.util.StringUtils; + +/** + * Created by fei + * on 16/06/28. + * Change by fei + * on 16/11/17 + * desc: translation detail + */ + +public class TranslationDetailFragment extends DetailFragment + implements TranslateDetailContract.View, OnCommentClickListener { + + private long mId; + private TextView mTVAuthorName; + private TextView mTVPubDate; + private TextView mTVTitle; + private ImageView mIVAuthorPortrait; + + private long mCommentId; + private long mCommentAuthorId; + private boolean mInputDoubleEmpty = false; + private DetailAboutView mAbouts; + private CoordinatorLayout mLayCoordinator; + private NestedScrollView mLayContent; + private View mLayBottom; + private LinearLayout mAboutSoftware; + + private CommentBar mDelegation; + + @Override + protected int getLayoutId() { + return R.layout.fragment_general_news_detail; + } + + + @Override + protected void initWidget(View root) { + super.initWidget(root); + + mTVAuthorName = (TextView) root.findViewById(R.id.tv_name); + mTVPubDate = (TextView) root.findViewById(R.id.tv_pub_date); + mTVTitle = (TextView) root.findViewById(R.id.tv_title); + + setGone(R.id.iv_info_view); + setGone(R.id.tv_info_view); + setGone(R.id.iv_info_comment); + + mIVAuthorPortrait = (ImageView) root.findViewById(R.id.iv_avatar); + mAbouts = (DetailAboutView) root.findViewById(R.id.lay_detail_about); + mAboutSoftware = (LinearLayout) root.findViewById(R.id.lay_about_software); + CommentView mComments = (CommentView) root.findViewById(R.id.lay_detail_comment); + mComments.setVisibility(View.GONE); + + mLayCoordinator = (CoordinatorLayout) root.findViewById(R.id.fragment_blog_detail); + mLayContent = (NestedScrollView) root.findViewById(R.id.lay_nsv); + + mLayBottom = root.findViewById(R.id.lay_option); + + mDelegation = CommentBar.delegation(getActivity(), mLayCoordinator); + + mDelegation.getBottomSheet().setCommitListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + handleSendComment(); + } + }); + + mDelegation.getBottomSheet().getEditText().setOnKeyListener(new View.OnKeyListener() { + @Override + public boolean onKey(View v, int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_DEL) { + handleKeyDel(); + } + return false; + } + }); + + mDelegation.setFavListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + handleFavorite(); + } + }); + mDelegation.setShareListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + handleShare(); + } + }); + + mDelegation.getBottomSheet().setMentionListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (AccountHelper.isLogin()) + SelectFriendsActivity.show(TranslationDetailFragment.this); + else + LoginActivity.show(getActivity()); + } + }); + + } + + @Override + protected void initData() { + final TranslationDetail translationDetail = mOperator.getData(); + if (translationDetail == null) + return; + + mId = mCommentId = translationDetail.getId(); + + setCommentCount(translationDetail.getCommentCount()); + setBodyContent(translationDetail.getBody()); + + mTVAuthorName.setText(translationDetail.getAuthor()); + getImgLoader().load(translationDetail.getAuthorPortrait()).error(R.mipmap.widget_dface).into(mIVAuthorPortrait); + + mTVPubDate.setText(StringUtils.formatSomeAgo(translationDetail.getPubDate())); + + mTVTitle.setText(translationDetail.getTitle()); + + toFavoriteOk(translationDetail); + + setText(R.id.tv_info_comment, translationDetail.getPubDate()); + + mAboutSoftware.setVisibility(View.GONE); + mAbouts.setVisibility(View.GONE); + } + + private void handleKeyDel() { + if (mCommentId != mId) { + if (TextUtils.isEmpty(mDelegation.getBottomSheet().getCommentText())) { + if (mInputDoubleEmpty) { + mCommentId = mId; + mCommentAuthorId = 0; + mDelegation.setCommentHint(getResources().getString(R.string.pub_comment_hint)); + mDelegation.getBottomSheet().getEditText().setHint(getResources().getString(R.string.pub_comment_hint)); + } else { + mInputDoubleEmpty = true; + } + } else { + mInputDoubleEmpty = false; + } + } + } + + + private void handleFavorite() { + mOperator.toFavorite(); + } + + private void handleShare() { + mOperator.toShare(); + } + + private void handleSendComment() { + mOperator.toSendComment(mId, mCommentId, mCommentAuthorId, mDelegation.getBottomSheet().getCommentText()); + } + + + @SuppressWarnings("deprecation") + @Override + public void toFavoriteOk(TranslationDetail translationDetail) { + if (translationDetail.isFavorite()) + mDelegation.setFavDrawable(R.drawable.ic_faved); + else + mDelegation.setFavDrawable(R.drawable.ic_fav); + } + + @Override + public void toSendCommentOk(Comment comment) { + if (mDelegation.getBottomSheet().isSyncToTweet()) { + TranslationDetail detail = mOperator.getData(); + if (detail == null) return; + TweetPublishService.startActionPublish(getActivity(), + mDelegation.getBottomSheet().getCommentText(), null, + About.buildShare(detail.getId(), OSChinaApi.COMMENT_TRANSLATION)); + } + Toast.makeText(getContext(), getResources().getString(R.string.pub_comment_success), Toast.LENGTH_SHORT).show(); + mDelegation.setCommentHint(getResources().getString(R.string.add_comment_hint)); + mDelegation.getBottomSheet().getEditText().setText(""); + mDelegation.getBottomSheet().getEditText().setHint(getResources().getString(R.string.add_comment_hint)); + // mComments.addComment(comment, getImgLoader(), this); + mDelegation.getBottomSheet().dismiss(); + } + + @Override + public void onClick(View view, Comment comment) { + FloatingAutoHideDownBehavior.showBottomLayout(mLayCoordinator, mLayContent, mLayBottom); + mCommentId = comment.getId(); + + + mCommentAuthorId = comment.getAuthor().getId(); + mDelegation.setCommentHint(String.format("%s %s", getResources().getString(R.string.reply_hint), + comment.getAuthor().getName())); + + mDelegation.getBottomSheet().show(String.format("%s %s", getResources().getString(R.string.reply_hint), + comment.getAuthor().getName())); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode == AppCompatActivity.RESULT_OK && data != null) { + mDelegation.getBottomSheet().handleSelectFriendsResult(data); + mDelegation.setCommentHint(mDelegation.getBottomSheet().getEditText().getHint().toString()); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/general/AboutAdapter.java b/app/src/main/java/net/oschina/app/improve/detail/general/AboutAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..e64abef14fd98e4d8b733fa825d94adf7e63a370 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/general/AboutAdapter.java @@ -0,0 +1,44 @@ +package net.oschina.app.improve.detail.general; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import net.oschina.app.R; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.bean.simple.About; + +/** + * Created by haibin + * on 2016/12/2. + */ + +public class AboutAdapter extends BaseRecyclerAdapter { + public AboutAdapter(Context context) { + super(context, NEITHER); + } + + @Override + protected RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type) { + return new AboutViewHolder(mInflater.inflate(R.layout.item_list_about, parent, false)); + } + + @Override + protected void onBindDefaultViewHolder(RecyclerView.ViewHolder holder, About item, int position) { + AboutViewHolder h = (AboutViewHolder) holder; + h.mTextTitle.setText(item.getTitle()); + ((AboutViewHolder) holder).mTextComCount.setText(String.valueOf(item.getCommentCount())); + } + + private static class AboutViewHolder extends RecyclerView.ViewHolder { + TextView mTextTitle, mTextComCount; + + public AboutViewHolder(View itemView) { + super(itemView); + mTextTitle = (TextView) itemView.findViewById(R.id.tv_title); + mTextComCount = (TextView) itemView.findViewById(R.id.tv_com_count); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/general/BlogDetailActivity.java b/app/src/main/java/net/oschina/app/improve/detail/general/BlogDetailActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..341748481f68f4c635610d9b53f73f78d7e241ab --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/general/BlogDetailActivity.java @@ -0,0 +1,29 @@ +package net.oschina.app.improve.detail.general; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; + +import net.oschina.app.improve.bean.SubBean; +import net.oschina.app.improve.detail.v2.DetailActivity; +import net.oschina.app.improve.detail.v2.DetailFragment; + +/** + * Created by haibin + * on 2016/11/30. + */ + +public class BlogDetailActivity extends DetailActivity { + public static void show(Context context, SubBean bean) { + Intent intent = new Intent(context, BlogDetailActivity.class); + Bundle bundle = new Bundle(); + bundle.putSerializable("sub_bean", bean); + intent.putExtras(bundle); + context.startActivity(intent); + } + + @Override + protected DetailFragment getDetailFragment() { + return BlogDetailFragment.newInstance(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/general/BlogDetailFragment.java b/app/src/main/java/net/oschina/app/improve/detail/general/BlogDetailFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..19f51b67e5d54ae8d251b1937507c969dc89e6b2 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/general/BlogDetailFragment.java @@ -0,0 +1,59 @@ +package net.oschina.app.improve.detail.general; + +import android.widget.TextView; + +import net.oschina.app.R; +import net.oschina.app.improve.bean.SubBean; +import net.oschina.app.improve.detail.v2.DetailFragment; +import net.oschina.app.util.StringUtils; + +import butterknife.Bind; +import de.hdodenhof.circleimageview.CircleImageView; + +/** + * Created by haibin + * on 2016/11/30. + */ + +public class BlogDetailFragment extends DetailFragment { + + @Bind(R.id.iv_avatar) + CircleImageView mImageAvatar; + + @Bind(R.id.tv_name) + TextView mTextName; + + @Bind(R.id.tv_pub_date) + TextView mTextPubDate; + + @Bind(R.id.tv_title) + TextView mTextTitle; + + @Bind(R.id.tv_info_comment) + TextView mTextComCount; + + @Bind(R.id.tv_info_view) + TextView mTextViewCount; + + public static BlogDetailFragment newInstance() { + BlogDetailFragment fragment = new BlogDetailFragment(); + return fragment; + } + + @Override + protected int getLayoutId() { + return R.layout.fragment_blog_detail_v2; + } + + + @Override + public void showGetDetailSuccess(SubBean bean) { + super.showGetDetailSuccess(bean); + mTextName.setText(bean.getAuthor().getName()); + getImgLoader().load(bean.getAuthor().getPortrait()).asBitmap().into(mImageAvatar); + mTextPubDate.setText(StringUtils.formatSomeAgo(bean.getPubDate())); + mTextTitle.setText(bean.getTitle()); + mTextComCount.setText(String.valueOf(bean.getStatistics().getComment())); + mTextViewCount.setText(String.valueOf(bean.getStatistics().getView())); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/general/NewsDetailActivity.java b/app/src/main/java/net/oschina/app/improve/detail/general/NewsDetailActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..0916839b5fec8e804fc532682ce77df8c6318c7c --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/general/NewsDetailActivity.java @@ -0,0 +1,29 @@ +package net.oschina.app.improve.detail.general; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; + +import net.oschina.app.improve.bean.SubBean; +import net.oschina.app.improve.detail.v2.DetailActivity; +import net.oschina.app.improve.detail.v2.DetailFragment; + +/** + * Created by haibin + * on 2016/11/30. + */ + +public class NewsDetailActivity extends DetailActivity { + public static void show(Context context, SubBean bean) { + Intent intent = new Intent(context, NewsDetailActivity.class); + Bundle bundle = new Bundle(); + bundle.putSerializable("sub_bean", bean); + intent.putExtras(bundle); + context.startActivity(intent); + } + + @Override + protected DetailFragment getDetailFragment() { + return NewsDetailFragment.newInstance(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/general/NewsDetailFragment.java b/app/src/main/java/net/oschina/app/improve/detail/general/NewsDetailFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..9b5cb7559af958112bc043e64b7603efebcc2293 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/general/NewsDetailFragment.java @@ -0,0 +1,43 @@ +package net.oschina.app.improve.detail.general; + +import android.widget.TextView; + +import net.oschina.app.R; +import net.oschina.app.improve.bean.SubBean; +import net.oschina.app.improve.detail.v2.DetailFragment; + +import butterknife.Bind; + +/** + * Created by haibin + * on 2016/11/30. + */ + +public class NewsDetailFragment extends DetailFragment { + @Bind(R.id.tv_title) + TextView mTextTitle; + + @Bind(R.id.tv_info_comment) + TextView mTextComCount; + + @Bind(R.id.tv_info_view) + TextView mTextViewCount; + + public static NewsDetailFragment newInstance() { + NewsDetailFragment fragment = new NewsDetailFragment(); + return fragment; + } + + @Override + protected int getLayoutId() { + return R.layout.fragment_news_detail_v2; + } + + @Override + public void showGetDetailSuccess(SubBean bean) { + super.showGetDetailSuccess(bean); + mTextTitle.setText(bean.getTitle()); + mTextComCount.setText(String.valueOf(bean.getStatistics().getComment())); + mTextViewCount.setText(String.valueOf(bean.getStatistics().getView())); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/sign/SignUpActivity.java b/app/src/main/java/net/oschina/app/improve/detail/sign/SignUpActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..539d4aeae066ba073230b1a6bcb1c327dcde064c --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/sign/SignUpActivity.java @@ -0,0 +1,81 @@ +package net.oschina.app.improve.detail.sign; + +import android.content.Intent; +import android.support.v4.app.Fragment; +import android.view.View; + +import net.oschina.app.R; +import net.oschina.app.improve.base.activities.BaseBackActivity; +import net.oschina.app.improve.widget.SimplexToast; +import net.oschina.app.ui.empty.EmptyLayout; + +import butterknife.Bind; + +/** + * 新版活动报名页面,动态请求活动报名参数,按服务器返回的顺序inflate各自对应的View + * Created by haibin + * on 2016/12/5. + */ + +public class SignUpActivity extends BaseBackActivity implements SignUpContract.EmptyView { + + @Bind(R.id.error_layout) + EmptyLayout mEmptyLayout; + + private SignUpFragment mFragment; + + private SignUpPresenter mPresenter; + + private long mSourceId; + + public static void show(Fragment fragment, long sourceId) { + Intent intent = new Intent(fragment.getActivity(), SignUpActivity.class); + intent.putExtra("sourceId", sourceId); + fragment.startActivityForResult(intent, 0x01); + } + + @Override + protected int getContentView() { + return R.layout.activity_sign_up; + } + + @Override + protected void initWidget() { + super.initWidget(); + mSourceId = getIntent().getLongExtra("sourceId", 0); + mFragment = SignUpFragment.newInstance(mSourceId); + addFragment(R.id.fl_content, mFragment); + mEmptyLayout.setErrorType(EmptyLayout.NETWORK_LOADING); + mEmptyLayout.setOnLayoutClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (mEmptyLayout.getErrorState() != EmptyLayout.NETWORK_LOADING) { + mEmptyLayout.setErrorType(EmptyLayout.NETWORK_LOADING); + mPresenter.getSignUpOptions(mSourceId); + } + } + }); + } + + @Override + protected void initData() { + super.initData(); + + if (mSourceId <= 0) { + SimplexToast.show(this, "活动资源不存在"); + finish(); + } + mPresenter = new SignUpPresenter(mFragment, this); + mPresenter.getSignUpOptions(mSourceId); + } + + @Override + public void hideEmptyLayout() { + mEmptyLayout.setErrorType(EmptyLayout.HIDE_LAYOUT); + } + + @Override + public void showErrorLayout(int errorType) { + mEmptyLayout.setErrorType(errorType); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/sign/SignUpContract.java b/app/src/main/java/net/oschina/app/improve/detail/sign/SignUpContract.java new file mode 100644 index 0000000000000000000000000000000000000000..0b83f2ab028fae3c234d2d8c77d1a03383cd9551 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/sign/SignUpContract.java @@ -0,0 +1,43 @@ +package net.oschina.app.improve.detail.sign; + +import net.oschina.app.improve.base.BasePresenter; +import net.oschina.app.improve.base.BaseView; +import net.oschina.app.improve.bean.SignUpEventOptions; + +import java.util.List; + +/** + * Created by haibin + * on 2016/12/5. + */ + +public interface SignUpContract { + + interface EmptyView { + void hideEmptyLayout(); + + void showErrorLayout(int errorType); + } + + interface View extends BaseView { + void showGetSignUpOptionsSuccess(List options); + + void showSignUpSuccess(); + + void showSignUpError(String message); + + void showInputEmpty(String message); + } + + interface Presenter extends BasePresenter { + /** + * 获得报名参数 + */ + void getSignUpOptions(long sourceId); + + /** + * 报名 + */ + void signUpEvent(long sourceId); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/sign/SignUpFragment.java b/app/src/main/java/net/oschina/app/improve/detail/sign/SignUpFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..17b7ca6b655bab39ac3c6b7ba22410993f21872b --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/sign/SignUpFragment.java @@ -0,0 +1,110 @@ +package net.oschina.app.improve.detail.sign; + +import android.app.Activity; +import android.app.ProgressDialog; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.LinearLayout; + +import net.oschina.app.R; +import net.oschina.app.improve.base.fragments.BaseFragment; +import net.oschina.app.improve.bean.SignUpEventOptions; +import net.oschina.app.improve.utils.DialogHelper; +import net.oschina.app.improve.widget.SimplexToast; + +import java.util.List; + +/** + * Created by haibin + * on 2016/12/5. + */ + +public class SignUpFragment extends BaseFragment implements SignUpContract.View { + private SignUpContract.Presenter mPresenter; + private LinearLayout mLayoutRoot; + private long mSourceId; + private ProgressDialog mDialog; + + public static SignUpFragment newInstance(long sourceId) { + SignUpFragment fragment = new SignUpFragment(); + Bundle bundle = new Bundle(); + bundle.putLong("sourceId", sourceId); + fragment.setArguments(bundle); + return fragment; + } + + @Override + protected int getLayoutId() { + return R.layout.fragment_sign_up; + } + + @Override + protected void initBundle(Bundle bundle) { + super.initBundle(bundle); + mSourceId = bundle.getLong("sourceId", 0); + } + + @Override + protected void initWidget(View root) { + super.initWidget(root); + mLayoutRoot = (LinearLayout) mRoot.findViewById(R.id.ll_root); + mDialog = DialogHelper.getProgressDialog(mContext); + } + + @Override + public void showGetSignUpOptionsSuccess(List options) { + mLayoutRoot.removeAllViews(); + for (SignUpEventOptions option : options) { + View view = ViewFactory.createView(getActivity(), mInflater, option); + if (view != null) + mLayoutRoot.addView(view); + } + View view = mInflater.inflate(R.layout.event_sign_up_button, null); + view.findViewById(R.id.btn_sign_up).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mPresenter.signUpEvent(mSourceId); + mDialog.setMessage("正在提交报名..."); + mDialog.show(); + } + }); + mLayoutRoot.addView(view); + } + + @Override + public void showSignUpSuccess() { + SimplexToast.show(mContext, "报名成功"); + Intent intent = new Intent(); + getActivity().setResult(Activity.RESULT_OK, intent); + mDialog.dismiss(); + getActivity().finish(); + } + + @Override + public void showSignUpError(String message) { + SimplexToast.show(mContext, message); + mDialog.dismiss(); + } + + @Override + public void showInputEmpty(String message) { + SimplexToast.show(mContext, message); + } + + @Override + public void setPresenter(SignUpContract.Presenter presenter) { + this.mPresenter = presenter; + } + + @Override + public void showNetworkError(int strId) { + SimplexToast.show(mContext, strId); + } + + @Override + public void onDestroy() { + mLayoutRoot.removeAllViews(); + super.onDestroy(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/sign/SignUpPresenter.java b/app/src/main/java/net/oschina/app/improve/detail/sign/SignUpPresenter.java new file mode 100644 index 0000000000000000000000000000000000000000..c32036afd7fbf6395cf14bbace06b8764cc7d845 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/sign/SignUpPresenter.java @@ -0,0 +1,129 @@ +package net.oschina.app.improve.detail.sign; + +import android.text.TextUtils; + +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.bean.EventDetail; +import net.oschina.app.improve.bean.SignUpEventOptions; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.ui.empty.EmptyLayout; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; + +import cz.msebera.android.httpclient.Header; + +/** + * Created by haibin + * on 2016/12/5. + */ + +class SignUpPresenter implements SignUpContract.Presenter { + private final SignUpContract.View mView; + private List mOptions; + private final SignUpContract.EmptyView mEmptyView; + + SignUpPresenter(SignUpContract.View mView, SignUpContract.EmptyView mEmptyView) { + this.mView = mView; + this.mEmptyView = mEmptyView; + this.mView.setPresenter(this); + } + + @Override + public void getSignUpOptions(long sourceId) { + OSChinaApi.getSignUpOptions(sourceId, new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + mEmptyView.showErrorLayout(EmptyLayout.NETWORK_ERROR); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + Type type = new TypeToken>>() { + }.getType(); + ResultBean> resultBean = AppOperator.createGson().fromJson(responseString, type); + if (resultBean.isSuccess()) { + mOptions = resultBean.getResult(); + mView.showGetSignUpOptionsSuccess(resultBean.getResult()); + mEmptyView.hideEmptyLayout(); + } else { + mEmptyView.showErrorLayout(EmptyLayout.NODATA); + } + } catch (Exception e) { + e.printStackTrace(); + mEmptyView.showErrorLayout(EmptyLayout.NODATA); + } + } + }); + } + + @Override + public void signUpEvent(long sourceId) { + if (!check()) + return; + + OSChinaApi.signUpEvent(sourceId, getOptions(), new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + mView.showNetworkError(R.string.tip_network_error); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + Type type = new TypeToken>() { + }.getType(); + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, type); + if (resultBean.isSuccess()) { + mView.showSignUpSuccess(); + } else { + mView.showSignUpError(resultBean.getMessage()); + } + } catch (Exception e) { + e.printStackTrace(); + mView.showSignUpError("报名失败"); + } + } + }); + } + + private boolean check() { + for (SignUpEventOptions options : mOptions) { + if (options.isRequired() && options.getSelectList() != null) { + if (options.getSelectList().size() == 0) { + mView.showInputEmpty(options.getLabel() + "不能为空"); + return false; + } + } + if (options.isRequired() && options.getValue() == null && TextUtils.isEmpty(options.getDefaultValue()) && options.getFormType() != SignUpEventOptions.FORM_TYPE_CHECK_BOX) { + mView.showInputEmpty(options.getLabel() + "不能为空"); + return false; + } + } + return true; + } + + private List getOptions() { + List ops = new ArrayList<>(); + for (SignUpEventOptions options : mOptions) { + if (options.getSelectList() == null) { + ops.add(options); + } else { + for (String s : options.getSelectList()) { + SignUpEventOptions sign = new SignUpEventOptions(); + sign.setKey(options.getKey()); + sign.setValue(s); + ops.add(sign); + } + } + } + return ops; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/sign/StringAdapter.java b/app/src/main/java/net/oschina/app/improve/detail/sign/StringAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..70afcb5c1406e48d8f1a06461bc544fb3ded15f2 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/sign/StringAdapter.java @@ -0,0 +1,63 @@ +package net.oschina.app.improve.detail.sign; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import net.oschina.app.R; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; + +/** + * Created by haibin + * on 2016/12/7. + */ + +class StringAdapter extends BaseRecyclerAdapter { + StringAdapter(Context context) { + super(context, NEITHER); + } + + @Override + protected RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type) { + return new SelectViewHolder(mInflater.inflate(R.layout.item_list_select, parent, false)); + } + + @Override + protected void onBindDefaultViewHolder(RecyclerView.ViewHolder holder, Select item, int position) { + SelectViewHolder h = (SelectViewHolder) holder; + h.mTextSelect.setText(item.getLabel()); + h.mTextSelect.setTextColor(item.isEnable() ? 0xff111111 : 0xff9A9A9A); + } + + private static class SelectViewHolder extends RecyclerView.ViewHolder { + TextView mTextSelect; + + SelectViewHolder(View itemView) { + super(itemView); + mTextSelect = (TextView) itemView.findViewById(R.id.tv_select); + } + } + + public static class Select { + private boolean enable; + private String label; + + public boolean isEnable() { + return enable; + } + + public void setEnable(boolean enable) { + this.enable = enable; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/sign/StringParams.java b/app/src/main/java/net/oschina/app/improve/detail/sign/StringParams.java new file mode 100644 index 0000000000000000000000000000000000000000..c268c3e2e3a3b90033bf6f13e4da71f6906a1367 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/sign/StringParams.java @@ -0,0 +1,62 @@ +package net.oschina.app.improve.detail.sign; + +import com.loopj.android.http.RequestParams; +import com.loopj.android.http.ResponseHandlerInterface; + +import java.io.IOException; +import java.util.IdentityHashMap; +import java.util.LinkedList; +import java.util.List; + +import cz.msebera.android.httpclient.HttpEntity; +import cz.msebera.android.httpclient.client.entity.UrlEncodedFormEntity; +import cz.msebera.android.httpclient.message.BasicNameValuePair; + +/** + * Created by haibin + * on 2016/12/8. + */ + +public class StringParams extends RequestParams { + private IdentityHashMap mParams = new IdentityHashMap<>(); + + public void putForm(String key, String value) { + mParams.put(new Param(key), value); + } + + @Override + public HttpEntity getEntity(ResponseHandlerInterface progressHandler) throws IOException { + UrlEncodedFormEntity entity = new UrlEncodedFormEntity(getParamsList(), contentEncoding); + return entity; + } + + protected List getParamsList() { + List lparams = new LinkedList(); + + for (IdentityHashMap.Entry entry : mParams.entrySet()) { + lparams.add(new BasicNameValuePair(entry.getKey().name, entry.getValue())); + } + return lparams; + } + + @Override + public String toString() { + return super.toString(); + } + + private static class Param { + private String name; + + public Param(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/sign/ViewFactory.java b/app/src/main/java/net/oschina/app/improve/detail/sign/ViewFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..ed5479ffacf48cf22edfd8664a4111f18ccc5e2b --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/sign/ViewFactory.java @@ -0,0 +1,281 @@ +package net.oschina.app.improve.detail.sign; + +import android.app.Activity; +import android.content.DialogInterface; +import android.support.v7.app.AlertDialog; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.text.Editable; +import android.text.InputType; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.RadioButton; +import android.widget.RadioGroup; +import android.widget.TextView; + +import net.oschina.app.R; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.bean.SignUpEventOptions; +import net.oschina.app.improve.utils.DialogHelper; +import net.oschina.app.improve.widget.FlowLayout; + +import java.util.ArrayList; + +/** + * Created by haibin + * on 2016/12/7. + */ + +final class ViewFactory { + static View createView(Activity activity, LayoutInflater inflater, final SignUpEventOptions options) { + View view = null; + switch (options.getFormType()) { + case SignUpEventOptions.FORM_TYPE_TEXT: + view = getEditTextView(activity, inflater, options, InputType.TYPE_CLASS_TEXT); + break; + case SignUpEventOptions.FORM_TYPE_TEXT_AREA: + view = getEditTextArea(activity, inflater, options); + break; + case SignUpEventOptions.FORM_TYPE_SELECT: + view = getSelect(activity, inflater, options); + break; + case SignUpEventOptions.FORM_TYPE_CHECK_BOX: + view = getCheckBox(activity, inflater, options); + break; + case SignUpEventOptions.FORM_TYPE_RADIO: + view = getRadios(activity, inflater, options); + break; + case SignUpEventOptions.FORM_TYPE_EMAIL: + view = getEditTextView(activity, inflater, options, InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS); + break; + case SignUpEventOptions.FORM_TYPE_DATE: + break; + case SignUpEventOptions.FORM_TYPE_MOBILE: + view = getEditTextView(activity, inflater, options, InputType.TYPE_CLASS_PHONE); + break; + case SignUpEventOptions.FORM_TYPE_NUMBER: + view = getEditTextView(activity, inflater, options, InputType.TYPE_CLASS_NUMBER); + break; + case SignUpEventOptions.FORM_TYPE_URL: + view = getEditTextView(activity, inflater, options, InputType.TYPE_TEXT_VARIATION_URI); + break; + default: + break; + } + return view; + } + + /** + * 当行输入 + */ + private static View getEditTextView(Activity activity, LayoutInflater inflater, final SignUpEventOptions options, int inputType) { + View view = inflater.inflate(R.layout.event_sign_up_edit_text, null); + ((TextView) view.findViewById(R.id.tv_label)).setText(options.getLabel() + (options.isRequired() ? "" : "(选填)") + ":"); + EditText editText = (EditText) view.findViewById(R.id.et_value); + editText.setText(options.getDefaultValue()); + options.setValue(options.getDefaultValue()); + editText.setInputType(inputType); + editText.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + options.setValue(s.toString()); + } + }); + return view; + } + + /** + * 多行输入的V + */ + private static View getEditTextArea(Activity activity, LayoutInflater inflater, final SignUpEventOptions options) { + View view = inflater.inflate(R.layout.event_sign_up_edit_text_area, null); + ((TextView) view.findViewById(R.id.tv_area)).setText(options.getLabel() + (options.isRequired() ? "" : "(选填)") + ":"); + EditText editText = (EditText) view.findViewById(R.id.et_area); + editText.setText(options.getDefaultValue()); + options.setValue(options.getDefaultValue()); + editText.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + options.setValue(s.toString()); + } + }); + return view; + } + + + private static View getRadios(Activity activity, LayoutInflater inflater, final SignUpEventOptions options) { + View view = inflater.inflate(R.layout.event_sign_up_radios, null); + RadioGroup radioGroup = (RadioGroup) view.findViewById(R.id.rg_options); + RadioGroup.LayoutParams params = new RadioGroup.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + params.setMarginEnd(100); + if (!TextUtils.isEmpty(options.getOption())) { + String[] list = options.getOption().split(";"); + String[] status = null; + if (!TextUtils.isEmpty(options.getOptionStatus())) + status = options.getOptionStatus().split(";"); + for (int i = 0; i < list.length; i++) { + RadioButton button = new RadioButton(activity); + button.setLayoutParams(params); + button.setText(list[i]); + if (!TextUtils.isEmpty(options.getDefaultValue())) { + button.setChecked(list[0].equals(options.getDefaultValue())); + options.setValue(options.getDefaultValue()); + } else { + button.setChecked(i == 0); + options.setValue(list[0]); + } + boolean enable; + if (status == null) + enable = true; + else if (status.length <= i) + enable = true; + else + enable = "0".equals(status[0]); + button.setId(i); + button.setEnabled(enable); + radioGroup.addView(button); + } + } + radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(RadioGroup group, int checkedId) { + String s[] = options.getOption().split(";"); + if (s != null) + options.setValue(s[checkedId]); + } + }); + return view; + } + + private static View getCheckBox(Activity activity, LayoutInflater inflater, final SignUpEventOptions options) { + View view = inflater.inflate(R.layout.event_sign_up_check_box, null); + FlowLayout ll_check_box = (FlowLayout) view.findViewById(R.id.fl_check_box); + RadioGroup.LayoutParams params = new RadioGroup.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + params.setMarginEnd(100); + if (options.getSelectList() == null) + options.setSelectList(new ArrayList()); + if (!TextUtils.isEmpty(options.getOption())) { + final String[] list = options.getOption().split(";"); + String[] status = null; + if (!TextUtils.isEmpty(options.getOptionStatus())) + status = options.getOptionStatus().split(";"); + for (int i = 0; i < list.length; i++) { + final CheckBox button = new CheckBox(activity); + button.setLayoutParams(params); + button.setText(list[i]); + boolean enable; + if (status == null) + enable = true; + else if (status.length <= i) + enable = true; + else + enable = "0".equals(status[i]); + button.setId(i); + button.setEnabled(enable); + button.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + String item = list[button.getId()]; + if (isChecked) { + options.getSelectList().add(item); + } else { + options.getSelectList().remove(item); + } + } + }); + ll_check_box.addView(button); + } + } + return view; + } + + private static View getSelect(Activity activity, LayoutInflater inflater, final SignUpEventOptions options) { + View view = inflater.inflate(R.layout.event_sign_up_select, null); + ((TextView) view.findViewById(R.id.tv_label)).setText(options.getLabel() + (options.isRequired() ? "" : "(选填)") + ":"); + final TextView tv_select = (TextView) view.findViewById(R.id.tv_select); + tv_select.setText(options.getDefaultValue()); + RecyclerView rv_select = (RecyclerView) inflater.inflate(R.layout.event_sign_up_select_list, null); + final StringAdapter adapter = new StringAdapter(activity); + rv_select.setLayoutManager(new LinearLayoutManager(activity)); + rv_select.setAdapter(adapter); + if (options.getOption() != null) { + String[] status = null; + if (!TextUtils.isEmpty(options.getOptionStatus())) + status = options.getOptionStatus().split(";"); + String[] list = options.getOption().split(";"); + for (int i = 0; i < list.length; i++) { + StringAdapter.Select s = new StringAdapter.Select(); + s.setLabel(list[i]); + boolean enable = false; + if (status == null) + enable = true; + else if (status.length <= i) + enable = true; + else + enable = "0".equals(status[i]); + s.setEnable(enable); + adapter.addItem(s); + } + } + + + final AlertDialog dialog = DialogHelper.getSelectDialog(activity, rv_select, "取消", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + } + }).create(); + + adapter.setOnItemClickListener(new BaseRecyclerAdapter.OnItemClickListener() { + @Override + public void onItemClick(int position, long itemId) { + StringAdapter.Select s = adapter.getItem(position); + if (s.isEnable()) { + tv_select.setText(s.getLabel()); + options.setValue(s.getLabel()); + dialog.dismiss(); + } + } + }); + + final LinearLayout linearLayout = (LinearLayout) view.findViewById(R.id.ll_select); + linearLayout.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + dialog.show(); + } + }); + return view; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/v2/DetailActivity.java b/app/src/main/java/net/oschina/app/improve/detail/v2/DetailActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..6be317c07417f4b4a83c85861f153cdb102fdb6e --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/v2/DetailActivity.java @@ -0,0 +1,141 @@ +package net.oschina.app.improve.detail.v2; + +import android.support.v7.app.AlertDialog; +import android.text.TextUtils; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; + +import net.oschina.app.R; +import net.oschina.app.improve.base.activities.BaseBackActivity; +import net.oschina.app.improve.bean.SubBean; +import net.oschina.app.improve.behavior.CommentBar; +import net.oschina.app.improve.dialog.ShareDialogBuilder; +import net.oschina.app.ui.empty.EmptyLayout; +import net.oschina.app.util.HTMLUtil; +import net.oschina.app.util.StringUtils; + +/** + * 新版本详情页实现 + * Created by haibin + * on 2016/11/30. + */ + +public abstract class DetailActivity extends BaseBackActivity implements DetailContract.EmptyView, Runnable { + private DetailPresenter mPresenter; + protected EmptyLayout mEmptyLayout; + protected DetailFragment mDetailFragment; + private ShareDialogBuilder mShareDialogBuilder; + protected AlertDialog mAlertDialog; + protected TextView mCommentCountView; + + protected CommentBar mDelegation; + private LinearLayout mLayComment; + + @Override + protected int getContentView() { + return R.layout.activity_detail_v2; + } + + @Override + protected void initWidget() { + super.initWidget(); + mLayComment = (LinearLayout) findViewById(R.id.ll_comment); + mEmptyLayout = (EmptyLayout) findViewById(R.id.lay_error); + mEmptyLayout.setOnLayoutClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (mEmptyLayout.getErrorState() != EmptyLayout.NETWORK_LOADING) { + mEmptyLayout.setErrorType(EmptyLayout.NETWORK_LOADING); + mPresenter.getDetail(); + } + } + }); + mDelegation = CommentBar.delegation(this, mLayComment); + mDetailFragment = getDetailFragment(); + addFragment(R.id.lay_container, mDetailFragment); + mPresenter = new DetailPresenter(mDetailFragment, this, (SubBean) getIntent().getSerializableExtra("sub_bean")); + mPresenter.getDetail(); + } + + @Override + public void hideEmptyLayout() { + mEmptyLayout.setErrorType(EmptyLayout.HIDE_LAYOUT); + } + + @Override + public void showErrorLayout(int errorType) { + mEmptyLayout.setErrorType(errorType); + } + + @Override + public void run() { + hideEmptyLayout(); + } + + int getOptionsMenuId() { + return R.menu.menu_detail; + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + int menuId = getOptionsMenuId(); + if (menuId <= 0) + return false; + MenuInflater inflater = getMenuInflater(); + inflater.inflate(menuId, menu); + MenuItem item = menu.findItem(R.id.menu_scroll_comment); + if (item != null) { + View action = item.getActionView(); + if (action != null) { + action.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (mDetailFragment != null) { + mDetailFragment.scrollToBottom(); + } + } + }); + View tv = action.findViewById(R.id.tv_comment_count); + if (tv != null) + mCommentCountView = (TextView) tv; + } + } + return true; + } + + + protected boolean toShare(String title, String content, String url) { + if (TextUtils.isEmpty(title) || TextUtils.isEmpty(content) || TextUtils.isEmpty(url)) + return false; + + content = content.trim(); + if (content.length() > 55) { + content = HTMLUtil.delHTMLTag(content); + if (content.length() > 55) + content = StringUtils.getSubString(0, 55, content); + } else { + content = HTMLUtil.delHTMLTag(content); + } + if (TextUtils.isEmpty(content)) + return false; + + // 分享 + if (mShareDialogBuilder == null) { + mShareDialogBuilder = ShareDialogBuilder.with(this) + .title(title) + .content(content) + .url(url) + .build(); + } + if (mAlertDialog == null) + mAlertDialog = mShareDialogBuilder.create(); + mAlertDialog.show(); + return true; + } + + protected abstract DetailFragment getDetailFragment(); +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/v2/DetailContract.java b/app/src/main/java/net/oschina/app/improve/detail/v2/DetailContract.java new file mode 100644 index 0000000000000000000000000000000000000000..9386d0bcb0d38f4fece54e9aae38ee34adab4161 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/v2/DetailContract.java @@ -0,0 +1,40 @@ +package net.oschina.app.improve.detail.v2; + +import net.oschina.app.improve.base.BasePresenter; +import net.oschina.app.improve.base.BaseView; +import net.oschina.app.improve.bean.SubBean; +import net.oschina.app.improve.bean.comment.Comment; + +/** + * Created by haibin + * on 2016/11/30. + */ + +public interface DetailContract { + + interface EmptyView { + void hideEmptyLayout(); + + void showErrorLayout(int errorType); + } + + interface View extends BaseView { + void showGetDetailSuccess(SubBean bean); + + void showFavReverseSuccess(boolean isFav, int strId); + + void showFavError(); + + void showCommentSuccess(Comment comment); + + void showCommentError(String message); + } + + interface Presenter extends BasePresenter { + void getDetail();//获得详情 + + void favReverse(); + + void addComment(String content, long sid, int type, long referId, long replyId, long oid);//添加评论 + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/v2/DetailFragment.java b/app/src/main/java/net/oschina/app/improve/detail/v2/DetailFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..c22734a51c419e939ff0437c7a729151c0870444 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/v2/DetailFragment.java @@ -0,0 +1,103 @@ +package net.oschina.app.improve.detail.v2; + +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.View; + +import net.oschina.app.R; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.base.fragments.BaseFragment; +import net.oschina.app.improve.bean.SubBean; +import net.oschina.app.improve.bean.comment.Comment; +import net.oschina.app.improve.bean.simple.About; +import net.oschina.app.improve.detail.general.AboutAdapter; +import net.oschina.app.improve.widget.OWebView; +import net.oschina.app.improve.widget.SimplexToast; + +import java.util.ArrayList; + +/** + * Created by haibin + * on 2016/11/30. + */ + +public class DetailFragment extends BaseFragment implements DetailContract.View, BaseRecyclerAdapter.OnItemClickListener { + protected DetailContract.Presenter mPresenter; + protected OWebView mWebView; + protected RecyclerView mRecyclerView; + protected AboutAdapter mAdapter; + + public static DetailFragment newInstance() { + DetailFragment fragment = new DetailFragment(); + return fragment; + } + + @Override + protected int getLayoutId() { + return R.layout.fragment_detail_v2; + } + + @Override + protected void initWidget(View root) { + super.initWidget(root); + mWebView = (OWebView) mRoot.findViewById(R.id.webView); + mRecyclerView = (RecyclerView) mRoot.findViewById(R.id.rv_about); + mAdapter = new AboutAdapter(getActivity()); + mAdapter.setOnItemClickListener(this); + mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); + mRecyclerView.setAdapter(mAdapter); + + } + + @Override + public void onItemClick(int position, long itemId) { + + } + + @Override + public void setPresenter(DetailContract.Presenter presenter) { + this.mPresenter = presenter; + } + + + @Override + public void showGetDetailSuccess(SubBean bean) { + if (mContext == null) return; + bean.setAbouts(new ArrayList()); + mAdapter.addAll(bean.getAbouts()); + mWebView.loadDetailDataAsync(bean.getBody(), (Runnable) mContext); + } + + @Override + public void showFavReverseSuccess(boolean isFav, int strId) { + SimplexToast.show(mContext, mContext.getResources().getString(strId)); + } + + @Override + public void showFavError() { + SimplexToast.show(mContext, "收藏失败"); + } + + @Override + public void showNetworkError(int strId) { + SimplexToast.show(mContext, mContext.getResources().getString(strId)); + } + + public void toShare(String title, String content, String url) { + ((DetailActivity) mContext).toShare(title, content, url); + } + + @Override + public void showCommentSuccess(Comment comment) { + + } + + @Override + public void showCommentError(String message) { + + } + + public void scrollToBottom() { + + } +} diff --git a/app/src/main/java/net/oschina/app/improve/detail/v2/DetailPresenter.java b/app/src/main/java/net/oschina/app/improve/detail/v2/DetailPresenter.java new file mode 100644 index 0000000000000000000000000000000000000000..75c79574240ed60428e261ae35d4d1bba4daf156 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/detail/v2/DetailPresenter.java @@ -0,0 +1,123 @@ +package net.oschina.app.improve.detail.v2; + +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.bean.Collection; +import net.oschina.app.improve.bean.SubBean; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.bean.comment.Comment; +import net.oschina.app.ui.empty.EmptyLayout; + +import java.lang.reflect.Type; + +import cz.msebera.android.httpclient.Header; + +/** + * Created by haibin + * on 2016/11/30. + */ + +public class DetailPresenter implements DetailContract.Presenter { + private final DetailContract.View mView; + private final DetailContract.EmptyView mEmptyView; + private SubBean mBean; + + public DetailPresenter(DetailContract.View mView, DetailContract.EmptyView mEmptyView, SubBean bean) { + this.mView = mView; + this.mBean = bean; + this.mEmptyView = mEmptyView; + this.mView.setPresenter(this); + } + + @Override + public void getDetail() { + OSChinaApi.getDetail(mBean.getType(), mBean.getId(), new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + //mView.showNetworkError(R.string.tip_network_error); + mEmptyView.showErrorLayout(EmptyLayout.NETWORK_ERROR); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + Type type = new TypeToken>() { + }.getType(); + ResultBean bean = AppOperator.createGson().fromJson(responseString, type); + if (bean.isSuccess()) { + mBean = bean.getResult(); + mView.showGetDetailSuccess(mBean); + } else { + mEmptyView.showErrorLayout(EmptyLayout.NODATA); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + + @Override + public void favReverse() { + OSChinaApi.getFavReverse(mBean.getId(), mBean.getType(), new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + mView.showFavError(); + mView.showNetworkError(R.string.tip_network_error); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + Type type = new TypeToken>() { + }.getType(); + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, type); + if (resultBean != null && resultBean.isSuccess()) { + Collection collection = resultBean.getResult(); + mView.showFavReverseSuccess(collection.isFavorite(), collection.isFavorite() ? R.string.add_favorite_success : R.string.del_favorite_success); + } else { + mView.showFavError(); + } + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + } + }); + } + + @Override + public void addComment(final String content, long sid, int type, long referId, long replyId, long oid) { + OSChinaApi.publishComment(sid, referId, replyId, oid, type, content, new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + mView.showNetworkError(R.string.tip_network_error); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + Type type = new TypeToken>() { + }.getType(); + + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, type); + if (resultBean.isSuccess()) { + Comment respComment = resultBean.getResult(); + if (respComment != null) { + mView.showCommentSuccess(respComment); + } + } else { + mView.showCommentError(resultBean.getMessage()); + } + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + } + }); + } +} diff --git a/app/src/main/java/net/oschina/app/ui/EventApplyDialog.java b/app/src/main/java/net/oschina/app/improve/dialog/EventDetailApplyDialog.java similarity index 52% rename from app/src/main/java/net/oschina/app/ui/EventApplyDialog.java rename to app/src/main/java/net/oschina/app/improve/dialog/EventDetailApplyDialog.java index 0a87f5dea75d6487094944efcc430dd412210917..47dbca3701fff2d8d017c94a8c7ed63368f6a877 100644 --- a/app/src/main/java/net/oschina/app/ui/EventApplyDialog.java +++ b/app/src/main/java/net/oschina/app/improve/dialog/EventDetailApplyDialog.java @@ -1,89 +1,85 @@ -package net.oschina.app.ui; +package net.oschina.app.improve.dialog; -import android.annotation.SuppressLint; import android.content.Context; import android.content.DialogInterface; import android.text.TextUtils; import android.view.View; import android.widget.EditText; +import android.widget.RadioButton; import android.widget.TextView; import net.oschina.app.AppContext; import net.oschina.app.R; -import net.oschina.app.bean.Event; import net.oschina.app.bean.EventApplyData; +import net.oschina.app.improve.bean.EventDetail; +import net.oschina.app.improve.utils.DialogHelper; import net.oschina.app.ui.dialog.CommonDialog; -import net.oschina.app.util.DialogHelp; +import java.util.Arrays; import java.util.List; +import java.util.regex.Pattern; +import butterknife.Bind; import butterknife.ButterKnife; -import butterknife.InjectView; -public class EventApplyDialog extends CommonDialog implements - android.view.View.OnClickListener { +public class EventDetailApplyDialog extends CommonDialog implements + View.OnClickListener { - @InjectView(R.id.et_name) + @Bind(R.id.et_name) EditText mName; - @InjectView(R.id.tv_gender) - TextView mGender; + @Bind(R.id.rb_male) + RadioButton rb_male; private String[] genders; - @InjectView(R.id.et_phone) + @Bind(R.id.et_phone) EditText mMobile; - @InjectView(R.id.et_company) + @Bind(R.id.et_company) EditText mCompany; - @InjectView(R.id.et_job) + @Bind(R.id.et_job) EditText mJob; - @InjectView(R.id.tv_remarks_tip) + @Bind(R.id.tv_remarks_tip) TextView mTvRemarksTip;// 备注提示 - @InjectView(R.id.tv_remarks_selecte) + @Bind(R.id.tv_remarks_selecte) TextView mTvRemarksSelected;// 备注选择 - private Event mEvent; + private EventDetail mEvent; - private EventApplyDialog(Context context, boolean flag, OnCancelListener listener) { + private EventDetailApplyDialog(Context context, boolean flag, OnCancelListener listener) { super(context, flag, listener); } - @SuppressLint("InflateParams") - private EventApplyDialog(Context context, int defStyle, Event event) { + private EventDetailApplyDialog(Context context, int defStyle, EventDetail event) { super(context, defStyle); - View shareView = getLayoutInflater().inflate( - R.layout.dialog_event_apply, null); - ButterKnife.inject(this, shareView); + View shareView = View.inflate(context, R.layout.dialog_event_detail_apply, null); + ButterKnife.bind(this, shareView); setContent(shareView, 0); this.mEvent = event; initView(); } private void initView() { - genders = getContext().getResources().getStringArray( - R.array.gender); + genders = getContext().getResources().getStringArray(R.array.gender); - mGender.setText(genders[0]); + rb_male.setChecked(true); - mGender.setOnClickListener(this); - - - if (mEvent.getEventRemark() != null) { + if (mEvent.getRemark() != null) { mTvRemarksTip.setVisibility(View.VISIBLE); - mTvRemarksTip.setText(mEvent.getEventRemark().getRemarkTip()); + mTvRemarksTip.setText(mEvent.getRemark().getTip()); mTvRemarksSelected.setVisibility(View.VISIBLE); mTvRemarksSelected.setOnClickListener(this); - - mTvRemarksSelected.setText(mEvent.getEventRemark().getSelect().getList().get(0)); + String[] selects = mEvent.getRemark().getSelect().split(","); + mTvRemarksSelected.setText(selects.length > 0 ? selects[0] : mEvent.getRemark().getSelect()); } } - public EventApplyDialog(Context context, Event event) { + public EventDetailApplyDialog(Context context, EventDetail event) { this(context, R.style.dialog_bottom, event); } @@ -91,9 +87,6 @@ public class EventApplyDialog extends CommonDialog implements public void onClick(View v) { int id = v.getId(); switch (id) { - case R.id.tv_gender: - selectGender(); - break; case R.id.tv_remarks_selecte: selectRemarkSelect(); break; @@ -102,30 +95,14 @@ public class EventApplyDialog extends CommonDialog implements } } - private void selectGender() { - String gender = mGender.getText().toString(); - int idx = 0; - for (int i = 0; i < genders.length; i++) { - if (genders[i].equals(gender)) { - idx = i; - break; - } - } - DialogHelp.getSelectDialog(getContext(), genders, new OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - mGender.setText(genders[i]); - } - }).show(); - } private void selectRemarkSelect() { - List stringList = mEvent.getEventRemark().getSelect().getList(); + List stringList = Arrays.asList(mEvent.getRemark().getSelect().split(",")); final String[] remarkSelects = new String[stringList.size()]; for (int i = 0; i < stringList.size(); i++) { remarkSelects[i] = stringList.get(i); } - DialogHelp.getSelectDialog(getContext(), remarkSelects, new OnClickListener() { + DialogHelper.getSelectDialog(getContext(), remarkSelects, "取消", new OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { mTvRemarksSelected.setText(remarkSelects[i]); @@ -135,7 +112,7 @@ public class EventApplyDialog extends CommonDialog implements public EventApplyData getApplyData() { String name = mName.getText().toString(); - String gender = mGender.getText().toString(); + String gender = genders[rb_male.isChecked() ? 0 : 1]; String phone = mMobile.getText().toString(); String company = mCompany.getText().toString(); String job = mJob.getText().toString(); @@ -151,8 +128,14 @@ public class EventApplyDialog extends CommonDialog implements return null; } - if (mEvent.getEventRemark() != null && TextUtils.isEmpty(remark)) { - AppContext.showToast("请" + mEvent.getEventRemark().getRemarkTip()); + Pattern pattern = Pattern.compile("^1(3[0-9]|4[57]|5[0-35-9]|7[01678]|8[0-9])[0-9]{7}[1-9]"); + if (!pattern.matcher(phone).find()) { + AppContext.showToast("请填写正确的手机号码"); + return null; + } + + if (mEvent.getRemark() != null && TextUtils.isEmpty(remark)) { + AppContext.showToast("请" + mEvent.getRemark().getTip()); return null; } @@ -164,7 +147,7 @@ public class EventApplyDialog extends CommonDialog implements data.setCompany(company); data.setJob(job); data.setRemark(remark); - + dismiss(); return data; } } diff --git a/app/src/main/java/net/oschina/app/improve/dialog/ShareDialogBuilder.java b/app/src/main/java/net/oschina/app/improve/dialog/ShareDialogBuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..2f617b698d7739eaf2a4c10e6916cffaa136481d --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/dialog/ShareDialogBuilder.java @@ -0,0 +1,458 @@ +package net.oschina.app.improve.dialog; + +import android.app.Activity; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.Uri; +import android.support.annotation.NonNull; +import android.support.annotation.StringRes; +import android.support.annotation.StyleRes; +import android.support.v7.app.AlertDialog; +import android.support.v7.widget.DefaultItemAnimator; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.Display; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.tencent.tauth.IUiListener; +import com.tencent.tauth.UiError; + +import net.oschina.app.AppContext; +import net.oschina.app.R; +import net.oschina.app.improve.bean.simple.About; +import net.oschina.app.improve.tweet.activities.TweetPublishActivity; +import net.oschina.app.improve.utils.DialogHelper; +import net.oschina.app.util.TDevice; +import net.oschina.open.bean.Share; +import net.oschina.open.constants.OpenConstant; +import net.oschina.open.factory.OpenBuilder; + +import java.util.ArrayList; +import java.util.List; + +import butterknife.Bind; +import butterknife.ButterKnife; + +/** + * 分享弹出框辅助类 + */ +public class ShareDialogBuilder extends AlertDialog.Builder implements + DialogInterface.OnCancelListener, DialogInterface.OnDismissListener, + OpenBuilder.Callback { + private Share mShare; + private About.Share mAboutShare; + private Activity mActivity; + private AlertDialog mAlertDialog; + private ProgressDialog mDialog; + + private ShareDialogBuilder(@NonNull Activity context, @StyleRes int themeResId) { + super(context, themeResId); + mActivity = context; + setTitle(null); + } + + public static ShareBuilder with(Activity activity) { + return with(activity, R.style.share_dialog); + } + + public static ShareBuilder with(@NonNull Activity activity, @StyleRes int themeResId) { + return new ShareBuilder(activity, themeResId); + } + + private List getAdapterData() { + List shareActions = new ArrayList<>(); + + //0.新浪微博 + shareActions.add(new ShareItem(R.mipmap.ic_login_3party_weibo, R.string.platform_sina)); + + //1.朋友圈 + shareActions.add(new ShareItem(R.mipmap.ic_action_moments, R.string.platform_wechat_circle)); + + //2.微信 + shareActions.add(new ShareItem(R.mipmap.ic_login_3party_wechat, R.string.platform_wechat)); + + //3.QQ + shareActions.add(new ShareItem(R.mipmap.ic_login_3party_qq, R.string.platform_qq)); + + //4.动弹 + if (About.check(mAboutShare)) { + shareActions.add(new ShareItem(R.mipmap.ic_action_tweet, R.string.platform_tweet)); + } + + //5.browser + shareActions.add(new ShareItem(R.mipmap.ic_action_browser, R.string.platform_browser)); + + //6.复制链接 + shareActions.add(new ShareItem(R.mipmap.ic_action_url, R.string.platform_copy_link)); + + //7.更多 + shareActions.add(new ShareItem(R.mipmap.ic_action_more, R.string.platform_more_option)); + + return shareActions; + } + + @SuppressWarnings("deprecation") + @Override + public AlertDialog create() { + + AlertDialog alertDialog = super.create(); + Window window = alertDialog.getWindow(); + + if (window != null) { + window.setGravity(Gravity.BOTTOM); + WindowManager m = window.getWindowManager(); + Display d = m.getDefaultDisplay(); + WindowManager.LayoutParams p = window.getAttributes(); + p.width = d.getWidth(); + window.setAttributes(p); + } + this.mAlertDialog = alertDialog; + return alertDialog; + } + + @Override + public AlertDialog.Builder setView(int layoutResId) { + AlertDialog.Builder builder = super.setView(layoutResId); + if (layoutResId == R.layout.dialog_share_main) { + LayoutInflater inflater = LayoutInflater.from(getContext()); + View contentView = inflater.inflate(layoutResId, null, false); + RecyclerView shareRecycle = (RecyclerView) contentView.findViewById(R.id.share_recycler); + shareRecycle.setAdapter(new ShareActionAdapter(getAdapterData())); + shareRecycle.setItemAnimator(new DefaultItemAnimator()); + shareRecycle.setLayoutManager(new GridLayoutManager(getContext(), 4)); + builder.setView(contentView); + builder.setOnCancelListener(this); + builder.setOnDismissListener(this); + } + return builder; + } + + public ShareDialogBuilder addShare(Share share) { + this.mShare = share; + return this; + } + + public ShareDialogBuilder boundActivity(Activity activity) { + this.mActivity = activity; + return this; + } + + @Override + public void onCancel(DialogInterface dialog) { + hideWaitDialog(); + } + + @Override + public void onDismiss(DialogInterface dialog) { + hideWaitDialog(); + } + + public void onItemClick(int position, ShareItem item) { + Share share = getShare(); + switch (item.iconId) { + //新浪微博 + case R.mipmap.ic_login_3party_weibo: + showWaitDialog(R.string.login_webo_hint); + OpenBuilder.with(mActivity) + .useWeibo(OpenConstant.WB_APP_KEY) + .share(share, this); + break; + //朋友圈 + case R.mipmap.ic_action_moments: + showWaitDialog(R.string.login_wechat_hint); + OpenBuilder.with(mActivity) + .useWechat(OpenConstant.WECHAT_APP_ID) + .shareTimeLine(share, this); + break; + //微信会话 + case R.mipmap.ic_login_3party_wechat: + showWaitDialog(R.string.login_wechat_hint); + OpenBuilder.with(mActivity) + .useWechat(OpenConstant.WECHAT_APP_ID) + .shareSession(share, this); + break; + //QQ + case R.mipmap.ic_login_3party_qq: + showWaitDialog(R.string.login_tencent_hint); + OpenBuilder.with(mActivity) + .useTencent(OpenConstant.QQ_APP_ID) + .share(share, new IUiListener() { + @Override + public void onComplete(Object o) { + hideWaitDialog(); + } + + @Override + public void onError(UiError uiError) { + hideWaitDialog(); + AppContext.showToast(R.string.share_hint, Toast.LENGTH_SHORT); + } + + @Override + public void onCancel() { + hideWaitDialog(); + } + }, this); + break; + //转发到动弹 + case R.mipmap.ic_action_tweet: + if (About.check(mAboutShare)) + TweetPublishActivity.show(getContext(), null, null, mAboutShare); + cancelLoading(); + break; + //在浏览器中打开 + case R.mipmap.ic_action_browser: + Intent intent = new Intent(); + intent.setAction(Intent.ACTION_VIEW); + // intent.setAction(Intent.CATEGORY_BROWSABLE); + Uri content_url = Uri.parse(share.getUrl()); + intent.setData(content_url); + mActivity.startActivity(intent); + cancelLoading(); + break; + //复制链接 + case R.mipmap.ic_action_url: + TDevice.copyTextToBoard(share.getUrl()); + cancelLoading(); + break; + //更多(调用系统分享) + default: + showSystemShareOption(share.getTitle(), share.getUrl()); + cancelLoading(); + break; + } + + } + + /** + * show WaitDialog + * + * @return progressDialog + */ + private ProgressDialog showWaitDialog(@StringRes int messageId) { + if (mDialog == null) { + if (messageId <= 0) { + mDialog = DialogHelper.getProgressDialog(mActivity, true); + } else { + String message = mActivity.getResources().getString(messageId); + mDialog = DialogHelper.getProgressDialog(mActivity, message, true); + } + } + mDialog.show(); + + return mDialog; + } + + /** + * hide waitDialog + */ + private void hideWaitDialog() { + ProgressDialog dialog = mDialog; + if (dialog != null) { + mDialog = null; + try { + dialog.cancel(); + // dialog.dismiss(); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + } + + public Share getShare() { + return mShare; + } + + /** + * 调用系统安装的应用分享 + * + * @param title title + * @param url url + */ + private void showSystemShareOption(final String title, final String url) { + Intent intent = new Intent(Intent.ACTION_SEND); + intent.setType("text/plain"); + intent.putExtra(Intent.EXTRA_SUBJECT, "分享:" + title); + intent.putExtra(Intent.EXTRA_TEXT, title + " " + url); + getContext().startActivity(Intent.createChooser(intent, "选择分享")); + } + + @Override + public void onFailed() { + hideWaitDialog(); + AppContext.showToast(R.string.share_hint, Toast.LENGTH_SHORT); + } + + @Override + public void onSuccess() { + //调起第三方客户端 +// if (mAlertDialog != null && mAlertDialog.isShowing()) { +// mAlertDialog.cancel(); +// //mAlertDialog.dismiss(); +// } + } + + /** + * cancelLoading + */ + public void cancelLoading() { + if (mAlertDialog != null && mAlertDialog.isShowing()) { + mAlertDialog.cancel(); + //mAlertDialog.dismiss(); + } + } + + public static class ShareBuilder { + private Activity activity; + private int themeResId; + private String title; + private String summary; + private String content; + private String description; + private String url; + private int bitmapResID = R.mipmap.ic_share; + private long id; + private int type; + + public ShareBuilder(Activity activity, int themeResId) { + this.activity = activity; + this.themeResId = themeResId; + } + + public ShareBuilder id(long id) { + this.id = id; + return this; + } + + public ShareBuilder type(int type) { + this.type = type; + return this; + } + + public ShareBuilder title(String title) { + this.title = title; + return this; + } + + public ShareBuilder content(String content) { + this.content = content; + this.summary = content; + this.description = content; + return this; + } + + public ShareBuilder url(String url) { + this.url = url; + return this; + } + + public ShareBuilder bitmapResID(int bitmapResID) { + this.bitmapResID = bitmapResID; + return this; + } + + public ShareDialogBuilder build() { + Share share = new Share(); + share.setTitle(title); + share.setSummary(summary); + share.setContent(content); + share.setDescription(description); + share.setUrl(url); + share.setBitmapResID(bitmapResID); + + share.setAppName("开源中国"); + share.setAppShareIcon(R.mipmap.ic_share); + + ShareDialogBuilder builder = new ShareDialogBuilder(activity, themeResId); + builder.mShare = share; + + if (id > 0 && type >= 0) { + About.Share aboutShare = About.buildShare(id, type); + aboutShare.title = title; + aboutShare.content = content; + builder.mAboutShare = aboutShare; + } + + builder.setView(R.layout.dialog_share_main); + return builder; + } + } + + private class ShareActionAdapter extends RecyclerView.Adapter + implements View.OnClickListener { + private List mShareActions; + + ShareActionAdapter(List shareActions) { + this.mShareActions = shareActions; + } + + @Override + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + Context context = parent.getContext(); + View rootView = LayoutInflater.from(context).inflate(R.layout.dialog_share_item, + parent, false); + ViewHolder viewHolder = new ViewHolder(rootView); + viewHolder.mIvIcon.setOnClickListener(this); + return viewHolder; + } + + @Override + public void onBindViewHolder(ViewHolder holder, int position) { + ShareItem shareAction = mShareActions.get(position); + holder.itemView.setTag(shareAction); + holder.mIvIcon.setImageResource(shareAction.iconId); + holder.mTvName.setText(shareAction.nameId); + holder.mIvIcon.setTag(holder); + } + + @Override + public int getItemCount() { + return mShareActions == null ? 0 : mShareActions.size(); + } + + @Override + public void onClick(View v) { + try { + ViewHolder viewHolder = (ViewHolder) v.getTag(); + int position = viewHolder.getAdapterPosition(); + ShareItem item = (ShareItem) viewHolder.itemView.getTag(); + onItemClick(position, item); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + + static class ViewHolder extends RecyclerView.ViewHolder { + @Bind(R.id.share_icon) + ImageView mIvIcon; + @Bind(R.id.share_name) + TextView mTvName; + + public ViewHolder(View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + } + + private static class ShareItem { + int iconId; + int nameId; + + ShareItem(int iconId, int nameId) { + this.iconId = iconId; + this.nameId = nameId; + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/emoji/EmojiGridView.java b/app/src/main/java/net/oschina/app/improve/emoji/EmojiGridView.java new file mode 100644 index 0000000000000000000000000000000000000000..c2060c015169ebe860ebce993836a9ad46f126b6 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/emoji/EmojiGridView.java @@ -0,0 +1,62 @@ +package net.oschina.app.improve.emoji; + +import android.content.Context; +import android.view.View; +import android.widget.AdapterView; +import android.widget.EditText; +import android.widget.GridView; + +import net.oschina.app.emoji.DisplayRules; +import net.oschina.app.emoji.EmojiGridAdapter; +import net.oschina.app.emoji.Emojicon; +import net.oschina.app.emoji.InputHelper; +import net.oschina.app.emoji.OnEmojiClickListener; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by haibin + * on 2016/11/10. + */ + +public class EmojiGridView extends GridView { + private List datas; + private EmojiGridAdapter adapter; + private OnEmojiClickListener listener; + private EditText mEditText; + + public EmojiGridView(Context context, EditText editText) { + super(context); + this.mEditText = editText; + setNumColumns(7); + init(); + } + + public void setListener(OnEmojiClickListener listener) { + this.listener = listener; + } + + private void init() { + setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, + int position, long id) { + if (listener != null) { + listener.onEmojiClick((Emojicon) parent.getAdapter() + .getItem(position)); + } + InputHelper.input2OSC(mEditText, (Emojicon) parent.getAdapter() + .getItem(position)); + } + }); + } + + public void initData(int type) { + datas = new ArrayList<>(); + datas = DisplayRules.getAllByType(type); + + adapter = new EmojiGridAdapter(getContext(), datas); + setAdapter(adapter); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/emoji/EmojiView.java b/app/src/main/java/net/oschina/app/improve/emoji/EmojiView.java new file mode 100644 index 0000000000000000000000000000000000000000..f828aa345e567b66ff5b76aee043d45ec0514463 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/emoji/EmojiView.java @@ -0,0 +1,96 @@ +package net.oschina.app.improve.emoji; + +import android.content.Context; +import android.support.v4.view.PagerAdapter; +import android.support.v4.view.ViewPager; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; +import android.widget.ImageButton; +import android.widget.LinearLayout; +import android.widget.TextView; + +import net.oschina.app.R; +import net.oschina.app.emoji.OnEmojiClickListener; + +/** + * Created by haibin + * on 2016/11/10. + */ + +public class EmojiView extends LinearLayout { + private ViewPager mEmpjiPager; + private TextView mQQText; + private TextView mEmojiText; + private ImageButton mDel; + private EditText mEditText; + private OnEmojiClickListener listener; + + public EmojiView(Context context, EditText editText) { + super(context); + this.mEditText = editText; + LayoutInflater.from(context).inflate(R.layout.layout_emoji, this, true); + } + + public void setListener(OnEmojiClickListener listener) { + this.listener = listener; + init(); + } + + private void init() { + mEmpjiPager = (ViewPager) findViewById(R.id.vp_emoji); + mQQText = (TextView) findViewById(R.id.tv_qq); + mEmojiText = (TextView) findViewById(R.id.tv_emoji); + mDel = (ImageButton) findViewById(R.id.ib_del); + + mQQText.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + mEmpjiPager.setCurrentItem(0); + } + }); + + mEmojiText.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + mEmpjiPager.setCurrentItem(1); + } + }); + + mDel.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + listener.onDeleteButtonClick(v); + } + }); + + mEmpjiPager.setAdapter(new PagerAdapter() { + @Override + public int getCount() { + return 2; + } + + @Override + public boolean isViewFromObject(View view, Object object) { + return view == object; + } + + @Override + public Object instantiateItem(ViewGroup container, int position) { + EmojiGridView view = new EmojiGridView(getContext(), mEditText); + view.setListener(listener); + container.addView(view); + view.initData(position); + return view; + } + + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + if (object instanceof EmojiGridView) { + container.removeView((EmojiGridView) object); + } + } + }); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/main/BrowserActivity.java b/app/src/main/java/net/oschina/app/improve/main/BrowserActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..28950c49520876d4a8d03db93ec84663c12d1a81 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/main/BrowserActivity.java @@ -0,0 +1,45 @@ +package net.oschina.app.improve.main; + +import net.oschina.app.R; +import net.oschina.app.improve.base.activities.BaseActivity; +import net.oschina.app.improve.widget.OWebView; + +import butterknife.Bind; + +public class BrowserActivity extends BaseActivity { + @Bind(R.id.webView) + protected OWebView mWebView; + + @Override + protected int getContentView() { + return R.layout.activity_browser; + } + + @Override + public void onResume() { + super.onResume(); + OWebView webView = mWebView; + if (webView != null) { + webView.onResume(); + } + } + + @Override + public void onPause() { + super.onPause(); + OWebView webView = mWebView; + if (webView != null) { + webView.onPause(); + } + } + + @Override + public void onDestroy() { + OWebView view = mWebView; + if (view != null) { + mWebView = null; + view.destroy(); + } + super.onDestroy(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/main/FeedBackActivity.java b/app/src/main/java/net/oschina/app/improve/main/FeedBackActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..df3e01cc5c0aa331e732f23b47ad30952e5902a4 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/main/FeedBackActivity.java @@ -0,0 +1,206 @@ +package net.oschina.app.improve.main; + +import android.app.ProgressDialog; +import android.content.Context; +import android.content.Intent; +import android.text.TextUtils; +import android.view.View; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.RadioButton; +import android.widget.Toast; + +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.base.activities.BaseBackActivity; +import net.oschina.app.improve.bean.Message; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.media.SelectImageActivity; +import net.oschina.app.improve.media.config.SelectOptions; +import net.oschina.app.improve.utils.PicturesCompressor; + +import java.io.File; +import java.lang.reflect.Type; + +import butterknife.Bind; +import butterknife.OnClick; +import cz.msebera.android.httpclient.Header; + +/** + * Created by haibin + * on 2016/10/14. + */ + +public class FeedBackActivity extends BaseBackActivity implements View.OnClickListener { + + @Bind(R.id.rb_error) + RadioButton rb_error; + + @Bind(R.id.et_feed_back) + EditText et_feed_back; + + @Bind(R.id.iv_add) + ImageView iv_add; + + @Bind(R.id.iv_clear_img) + ImageView iv_clear_img; + + private String mFilePath = ""; + private String mFeedbackStr = "[Android-主站-%s]"; + private ProgressDialog mDialog; + + public static void show(Context context) { + context.startActivity(new Intent(context, FeedBackActivity.class)); + } + + @Override + protected int getContentView() { + return R.layout.activity_feed_back; + } + + @Override + protected void initWidget() { + super.initWidget(); + rb_error.setChecked(true); + } + + @Override + protected void initData() { + super.initData(); + } + + @OnClick({R.id.iv_add, R.id.iv_clear_img}) + @Override + public void onClick(View view) { + switch (view.getId()) { + case R.id.btn_commit: + String content = getFeedBackContent(); + if (TextUtils.isEmpty(content) && TextUtils.isEmpty(mFilePath)) { + return; + } + content = String.format(mFeedbackStr, rb_error.isChecked() ? "程序错误" : "功能建议") + content; + File file = new File(mFilePath); + if (file.exists()) { + compress(mFilePath, new Run(content)); + } else { + addFeedBack(content, null); + } + break; + case R.id.iv_add: + openImageSelector(); + break; + case R.id.iv_clear_img: + iv_add.setImageResource(R.mipmap.ic_tweet_add); + iv_clear_img.setVisibility(View.GONE); + mFilePath = ""; + break; + } + } + + public void openImageSelector() { + SelectImageActivity.show(this, new SelectOptions.Builder() + .setHasCam(false) + .setSelectCount(1) + .setCallback(new SelectOptions.Callback() { + @Override + public void doSelected(String[] images) { + mFilePath = images[0]; + getImageLoader().load(mFilePath).into(iv_add); + iv_clear_img.setVisibility(View.VISIBLE); + } + }).build()); + } + + /** + * 添加反馈,走系统私信接口 + * + * @param content content + * @param file file + */ + private void addFeedBack(String content, File file) { + getDialog("反馈中...").show(); + OSChinaApi.pubMessage(2609904, content, file, new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + Toast.makeText(FeedBackActivity.this, "网络错误,请重试", Toast.LENGTH_SHORT).show(); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + Type type = new TypeToken>() { + }.getType(); + try { + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, type); + if (resultBean.isSuccess()) { + Toast.makeText(FeedBackActivity.this, "谢谢您的反馈", Toast.LENGTH_SHORT).show(); + finish(); + } else { + Toast.makeText(FeedBackActivity.this, resultBean.getMessage(), Toast.LENGTH_SHORT).show(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void onFinish() { + super.onFinish(); + mDialog.dismiss(); + } + }); + } + + private void compress(final String oriPath, final Run runnable) { + final String path = getFilesDir() + "/message/" + getFileName(oriPath); + AppOperator.runOnThread(new Runnable() { + @Override + public void run() { + if (PicturesCompressor.compressImage(oriPath, path, 512 * 1024)) { + runnable.setPath(path); + runOnUiThread(runnable); + } + } + }); + } + + private String getFileName(String filePath) { + return filePath.substring(filePath.lastIndexOf("/") + 1); + } + + private class Run implements Runnable { + private String path; + private String content; + + public Run(String content) { + this.content = content; + } + + @Override + public void run() { + File file = new File(path); + addFeedBack(content, file); + } + + public void setPath(String path) { + this.path = path; + } + } + + public String getFeedBackContent() { + return et_feed_back.getText().toString().trim(); + } + + public ProgressDialog getDialog(String message) { + if (mDialog == null) { + mDialog = new ProgressDialog(this); + mDialog.setCancelable(false); + mDialog.setCanceledOnTouchOutside(false); + } + mDialog.setMessage(message); + return mDialog; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/main/MainActivity.java b/app/src/main/java/net/oschina/app/improve/main/MainActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..7953ea52de4f284d6b162caed6babffaa1eaa1c8 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/main/MainActivity.java @@ -0,0 +1,238 @@ +package net.oschina.app.improve.main; + +import android.Manifest; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.os.SystemClock; +import android.provider.Settings; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.LinearInterpolator; +import android.widget.LinearLayout; +import android.widget.Toast; + +import net.oschina.app.AppConfig; +import net.oschina.app.AppContext; +import net.oschina.app.R; +import net.oschina.app.base.BaseApplication; +import net.oschina.app.improve.base.activities.BaseActivity; +import net.oschina.app.improve.bean.Version; +import net.oschina.app.improve.main.nav.NavFragment; +import net.oschina.app.improve.main.nav.NavigationButton; +import net.oschina.app.improve.main.update.CheckUpdateManager; +import net.oschina.app.improve.main.update.DownloadService; +import net.oschina.app.improve.notice.NoticeManager; +import net.oschina.app.improve.utils.DialogHelper; +import net.oschina.app.interf.OnTabReselectListener; + +import java.util.ArrayList; +import java.util.List; + +import butterknife.Bind; +import pub.devrel.easypermissions.AfterPermissionGranted; +import pub.devrel.easypermissions.EasyPermissions; + +public class MainActivity extends BaseActivity implements + NavFragment.OnNavigationReselectListener, + EasyPermissions.PermissionCallbacks, + CheckUpdateManager.RequestPermissions { + + private final int RC_EXTERNAL_STORAGE = 0x04;//存储权限 + public static final String ACTION_NOTICE = "ACTION_NOTICE"; + private long mBackPressedTime; + + private Version mVersion; + + @Bind(R.id.activity_main_ui) + LinearLayout mMainUi; + + private NavFragment mNavBar; + private List mTurnBackListeners = new ArrayList<>(); + + public interface TurnBackListener { + boolean onTurnBack(); + } + + @Override + protected int getContentView() { + return R.layout.activity_main_ui; + } + + @Override + protected void initWidget() { + super.initWidget(); + FragmentManager manager = getSupportFragmentManager(); + mNavBar = ((NavFragment) manager.findFragmentById(R.id.fag_nav)); + mNavBar.setup(this, manager, R.id.main_container, this); + + if (AppContext.get("isFirstComing", true)) { + View view = findViewById(R.id.layout_ripple); + view.setVisibility(View.VISIBLE); + view.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + ((ViewGroup) v.getParent()).removeView(v); + AppContext.set("isFirstComing", false); + } + }); + } + } + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + doNewIntent(getIntent(), true); + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + doNewIntent(intent, false); + } + + private void doNewIntent(Intent intent, boolean isCreate) { + if (intent == null || intent.getAction() == null) + return; + String action = intent.getAction(); + if (action.equals(ACTION_NOTICE)) { + NavFragment bar = mNavBar; + if (bar != null) { + bar.select(3); + } + } + } + + @Override + public void onReselect(NavigationButton navigationButton) { + Fragment fragment = navigationButton.getFragment(); + if (fragment != null + && fragment instanceof OnTabReselectListener) { + OnTabReselectListener listener = (OnTabReselectListener) fragment; + listener.onTabReselect(); + } + } + + @Override + protected void initData() { + super.initData(); + NoticeManager.init(this); + // in this we can checkShare update + checkUpdate(); + } + + @Override + public void call(Version version) { + this.mVersion = version; + requestExternalStorage(); + } + + @AfterPermissionGranted(RC_EXTERNAL_STORAGE) + public void requestExternalStorage() { + if (EasyPermissions.hasPermissions(this, Manifest.permission.READ_EXTERNAL_STORAGE)) { + DownloadService.startService(this, mVersion.getDownloadUrl()); + } else { + EasyPermissions.requestPermissions(this, "", RC_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE); + } + } + + + @Override + public void onPermissionsGranted(int requestCode, List perms) { + + } + + @Override + public void onPermissionsDenied(int requestCode, List perms) { + DialogHelper.getConfirmDialog(this, "温馨提示", "需要开启开源中国对您手机的存储权限才能下载安装,是否现在开启", "去开启", "取消", false, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + startActivity(new Intent(Settings.ACTION_APPLICATION_SETTINGS)); + } + }, null).show(); + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + NoticeManager.stopListen(this); + } + + public void addOnTurnBackListener(TurnBackListener l) { + this.mTurnBackListeners.add(l); + } + + public void toggleNavTabView(boolean isShowOrHide) { + final View view = mNavBar.getView(); + if (view == null) return; + // hide + view.setVisibility(View.VISIBLE); + if (!isShowOrHide) { + view.animate() + .translationY(view.getHeight()) + .setDuration(180) + .setInterpolator(new LinearInterpolator()) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + view.setTranslationY(view.getHeight()); + view.setVisibility(View.GONE); + } + }); + } else { + view.animate() + .translationY(0) + .setDuration(180) + .setInterpolator(new LinearInterpolator()) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + // fix:bug > 点击隐藏的同时,快速点击显示 + view.setVisibility(View.VISIBLE); + view.setTranslationY(0); + } + }); + } + } + + @Override + public void onBackPressed() { + for (TurnBackListener l : mTurnBackListeners) { + if (l.onTurnBack()) return; + } + boolean isDoubleClick = BaseApplication.get(AppConfig.KEY_DOUBLE_CLICK_EXIT, true); + if (isDoubleClick) { + long curTime = SystemClock.uptimeMillis(); + if ((curTime - mBackPressedTime) < (3 * 1000)) { + finish(); + } else { + mBackPressedTime = curTime; + Toast.makeText(this, R.string.tip_double_click_exit, Toast.LENGTH_LONG).show(); + } + } else { + finish(); + } + } + + private void checkUpdate() { + if (!AppContext.get(AppConfig.KEY_CHECK_UPDATE, true)) { + return; + } + CheckUpdateManager manager = new CheckUpdateManager(this, false); + manager.setCaller(this); + manager.checkUpdate(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/main/banner/EventHeaderView.java b/app/src/main/java/net/oschina/app/improve/main/banner/EventHeaderView.java new file mode 100644 index 0000000000000000000000000000000000000000..edb4ad04554f4e53de02401495b83b21ac149e5b --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/main/banner/EventHeaderView.java @@ -0,0 +1,42 @@ +package net.oschina.app.improve.main.banner; + +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; + +import com.bumptech.glide.RequestManager; + +import net.oschina.app.R; +import net.oschina.app.bean.Banner; +import net.oschina.app.improve.widget.ViewEventBanner; +import net.oschina.app.util.UIHelper; + +/** + * Created by haibin + * on 2016/10/26. + */ + +public class EventHeaderView extends HeaderView { + public EventHeaderView(Context context, RequestManager loader, String api, String bannerCache) { + super(context, loader, api, bannerCache); + } + + @Override + protected int getLayoutId() { + return R.layout.banner_event; + } + + @Override + protected View instantiateItem(ViewGroup container, int position) { + ViewEventBanner view = new ViewEventBanner(getContext()); + view.initData(mImageLoader, mBanners.get(position)); + container.addView(view); + return view; + } + + @Override + public void onItemClick(int position) { + Banner banner = mBanners.get(position); + UIHelper.showBannerDetail(getContext(), banner); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/main/banner/HeaderView.java b/app/src/main/java/net/oschina/app/improve/main/banner/HeaderView.java new file mode 100644 index 0000000000000000000000000000000000000000..1b2225b6d5c4d16bf699409723b8f7036bc68c8b --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/main/banner/HeaderView.java @@ -0,0 +1,161 @@ +package net.oschina.app.improve.main.banner; + +import android.content.Context; +import android.os.Handler; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.RelativeLayout; + +import com.bumptech.glide.RequestManager; +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.bean.Banner; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.bean.base.PageBean; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.utils.CacheManager; +import net.oschina.app.improve.widget.indicator.BannerView; +import net.oschina.app.improve.widget.indicator.CircleBannerIndicator; + +import java.util.ArrayList; +import java.util.List; + +import cz.msebera.android.httpclient.Header; + +/** + * Created by haibin + * on 2016/10/26. + */ + +public abstract class HeaderView extends RelativeLayout implements BannerView.OnViewChangeListener, BannerView.OnItemClickListener, Runnable { + protected BannerView mBannerView; + protected CircleBannerIndicator mIndicator; + protected List mBanners; + protected BannerAdapter mAdapter; + protected Handler mHandler; + protected int mCurrentItem; + protected RequestManager mImageLoader; + protected TextHttpResponseHandler mCallBack; + protected String mUrl; + private boolean isScrolling; + protected String mBannerCache; + private boolean isStop; + + public HeaderView(Context context, RequestManager loader, String api, String bannerCache) { + super(context); + mImageLoader = loader; + this.mUrl = api; + this.mBannerCache = bannerCache; + init(context); + } + + protected void init(Context context) { + mHandler = new Handler(); + mBanners = new ArrayList<>(); + + List banners = CacheManager.readListJson(context, mBannerCache, Banner.class); + if (banners != null) { + mBanners.addAll(banners); + mHandler.postDelayed(this, 5000); + } + LayoutInflater.from(context).inflate(getLayoutId(), this, true); + mBannerView = (BannerView) findViewById(R.id.banner); + mIndicator = (CircleBannerIndicator) findViewById(R.id.indicator); + mAdapter = new BannerAdapter(); + mBannerView.addOnViewChangeListener(this); + mBannerView.setAdapter(mAdapter); + mBannerView.setOnItemClickListener(this); + mIndicator.bindBannerView(mBannerView); + mCallBack = new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + ResultBean> result = AppOperator.createGson().fromJson(responseString, + new TypeToken>>() { + }.getType()); + if (result != null && result.isSuccess()) { + CacheManager.saveToJson(getContext(), mBannerCache, result.getResult().getItems()); + setBanners(result.getResult().getItems()); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + }; + requestBanner(); + } + + @Override + public void run() { + mHandler.postDelayed(this, 5000); + if (isScrolling) + return; + mCurrentItem = (mCurrentItem + 1) % mBanners.size(); + mBannerView.setCurrentItem(mCurrentItem); + } + + public void requestBanner() { + OSChinaApi.getBanner(mUrl, mCallBack); + } + + void setBanners(List banners) { + if (banners != null) { + mHandler.removeCallbacks(this); + mBanners.clear(); + mBanners.addAll(banners); + mBannerView.getAdapter().notifyDataSetChange(); + mIndicator.notifyDataSetChange(); + if (mBanners.size() > 1) { + mHandler.postDelayed(this, 5000); + } + } + } + + protected abstract int getLayoutId(); + + protected abstract View instantiateItem(ViewGroup container, int position); + + + @Override + public void onViewScrolled(int position, float positionOffset) { + isScrolling = mCurrentItem != position; + isStop = true; + mHandler.removeCallbacks(this); + } + + @Override + public void onViewSelected(int position) { + isScrolling = false; + mCurrentItem = position; + if (isStop) { + mHandler.postDelayed(HeaderView.this, 5000); + } + isStop = false; + } + + @Override + public void onViewStateChanged(int state) { + isScrolling = state == BannerView.OnViewChangeListener.STATE_DRAGGING; + } + + private class BannerAdapter extends BannerView.ViewAdapter { + @Override + public int getCount() { + return mBanners.size(); + } + + @Override + public View instantiateItem(ViewGroup parent, int position) { + return HeaderView.this.instantiateItem(parent, position); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/main/banner/NewsHeaderView.java b/app/src/main/java/net/oschina/app/improve/main/banner/NewsHeaderView.java new file mode 100644 index 0000000000000000000000000000000000000000..3aad699ae6bcc067316ec777f8255b78f4b5fa00 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/main/banner/NewsHeaderView.java @@ -0,0 +1,71 @@ +package net.oschina.app.improve.main.banner; + +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.bumptech.glide.RequestManager; + +import net.oschina.app.R; +import net.oschina.app.bean.Banner; +import net.oschina.app.improve.widget.ViewNewsBanner; +import net.oschina.app.util.UIHelper; + +import java.util.List; + +/** + * Created by haibin + * on 2016/10/26. + */ + +public class NewsHeaderView extends HeaderView { + private TextView mTitleTextView; + + public NewsHeaderView(Context context, RequestManager loader, String api, String bannerCache) { + super(context, loader, api, bannerCache); + } + + @Override + protected void init(Context context) { + super.init(context); + mTitleTextView = (TextView) findViewById(R.id.tv_title); + } + + @Override + protected int getLayoutId() { + return R.layout.banner_news; + } + + @Override + public void onViewSelected(int position) { + super.onViewSelected(position); + mTitleTextView.setText(mBanners.get(position).getName()); + } + + @Override + void setBanners(List banners) { + if (banners.size() > 0 && mBanners.size() == 0) { + mTitleTextView.setText(banners.get(0).getName()); + } + super.setBanners(banners); + } + + @Override + protected View instantiateItem(ViewGroup container, int position) { + ViewNewsBanner view = new ViewNewsBanner(getContext()); + view.initData(mImageLoader, mBanners.get(position)); + container.addView(view); + return view; + } + + @Override + public void onItemClick(int position) { + Banner banner = mBanners.get(position); + if (banner != null) { + int type = banner.getType(); + long id = banner.getId(); + UIHelper.showDetail(getContext(), type, id, banner.getHref()); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/main/discover/BaseSensorFragment.java b/app/src/main/java/net/oschina/app/improve/main/discover/BaseSensorFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..5c5c23ba6c2a7077692c20136c2e86185c3edc94 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/main/discover/BaseSensorFragment.java @@ -0,0 +1,228 @@ +package net.oschina.app.improve.main.discover; + +import android.app.Service; +import android.content.Context; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.media.MediaPlayer; +import android.os.Handler; +import android.os.Vibrator; +import android.support.v7.widget.CardView; +import android.view.View; +import android.view.animation.Animation; +import android.view.animation.ScaleAnimation; +import android.widget.TextView; + +import com.google.gson.GsonBuilder; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.R; +import net.oschina.app.improve.base.fragments.BaseFragment; +import net.oschina.app.improve.bean.base.ResultBean; +import net.qiujuer.genius.ui.widget.Loading; + +import java.lang.reflect.Type; + +import butterknife.Bind; +import cz.msebera.android.httpclient.Header; + +/** + * 摇一摇基本逻辑实现 + */ +public abstract class BaseSensorFragment extends BaseFragment implements SensorEventListener, View.OnClickListener { + public static final int UPTATE_INTERVAL_TIME = 50; + + protected SensorManager mSensor = null; + protected Vibrator mVibrator = null; + protected int mSpeedThreshold = 45;// 这个值越大需要越大的力气来摇晃手机 + + private float mSensorLastX; + private float mSensorLastY; + private float mSensorLastZ; + private long mSensorLastUpdateTime; + + protected boolean mLoading; + protected boolean mIsRegister; + protected int mDelayTime = 5; + + protected TextHttpResponseHandler mHandler; + protected ResultBean mBean; + protected View mShakeView; + + @Bind(R.id.cv_shake) + CardView mCardView; + + @Bind(R.id.tv_state) + TextView mTvState; + + @Bind(R.id.loading) + Loading mLoadingView; + + @Bind(R.id.tv_time) + TextView mTxtTime; + + protected Handler mTimeHandler; + + @Override + protected void initWidget(View root) { + super.initWidget(root); + mSensor = (SensorManager) getActivity() + .getSystemService(Context.SENSOR_SERVICE); + mVibrator = (Vibrator) getActivity().getSystemService(Service.VIBRATOR_SERVICE); + mCardView.setOnClickListener(this); + } + + @Override + protected void initData() { + super.initData(); + mHandler = new TextHttpResponseHandler() { + @Override + public void onStart() { + super.onStart(); + BaseSensorFragment.this.onRequestStart(); + } + + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + if (mContext != null) { + BaseSensorFragment.this.onFailure(); + } + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + if (mContext == null) + return; + try { + mBean = new GsonBuilder().create().fromJson(responseString, getType()); + if (mBean != null && mBean.isSuccess()) { + BaseSensorFragment.this.onSuccess(); + } else { + onFailure(statusCode, headers, responseString, new Exception()); + } + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + } + + @Override + public void onFinish() { + super.onFinish(); + onTimeProgress(); + } + }; + } + + @Override + public void onClick(View v) { + + } + + @Override + public void onDetach() { + super.onDetach(); + mTimeHandler = null; + } + + public void onShake() { + + } + + + protected void initShakeView() { + + } + + protected void onTimeProgress() { + + } + + protected void onRequestStart() { + mTvState.setVisibility(View.VISIBLE); + mTvState.setText("正在搜寻礼品"); + mLoadingView.setVisibility(View.VISIBLE); + mLoadingView.start(); + } + + protected void onSuccess() { + mCardView.removeAllViews(); + MediaPlayer.create(mContext, R.raw.shake).start(); + initShakeView(); + mCardView.addView(mShakeView); + mCardView.setVisibility(View.VISIBLE); + ScaleAnimation animation = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f, + Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); + animation.setDuration(320); + animation.setFillAfter(true); + mCardView.startAnimation(animation); + + mLoadingView.stop(); + mLoadingView.setVisibility(View.GONE); + mTvState.setVisibility(View.GONE); + } + + + protected void onFailure() { + mTvState.setText("很遗憾,你没有摇到礼品,请再试一次"); + } + + @Override + public void onSensorChanged(SensorEvent event) { + long currentUpdateTime = System.currentTimeMillis(); + long timeInterval = currentUpdateTime - mSensorLastUpdateTime; + if (timeInterval < UPTATE_INTERVAL_TIME) { + return; + } + mSensorLastUpdateTime = currentUpdateTime; + + float x = event.values[0]; + float y = event.values[1]; + float z = event.values[2]; + + float deltaX = x - mSensorLastX; + float deltaY = y - mSensorLastY; + float deltaZ = z - mSensorLastZ; + + mSensorLastX = x; + mSensorLastY = y; + mSensorLastZ = z; + + double speed = (Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ + * deltaZ) / timeInterval) * 100; + if (speed >= mSpeedThreshold && !mLoading) { + mLoading = true; + mVibrator.vibrate(300); + onShake(); + } + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + + } + + public void registerSensor() { + if (mSensor != null && !mIsRegister) { + Sensor sensor = mSensor.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); + if (sensor != null) { + mIsRegister = true; + mSensor.registerListener(this, sensor, + SensorManager.SENSOR_DELAY_GAME); + } + } + } + + public void unregisterSensor() { + if (mSensor != null && mIsRegister) { + mIsRegister = false; + mSensor.unregisterListener(this); + } + } + + protected Type getType() { + return null; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/main/discover/QRCodeActivity.java b/app/src/main/java/net/oschina/app/improve/main/discover/QRCodeActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..4763cf4bbed1a8555797fbb53365d1679663a2a9 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/main/discover/QRCodeActivity.java @@ -0,0 +1,15 @@ +package net.oschina.app.improve.main.discover; + +import net.oschina.app.improve.base.activities.BaseActivity; + +/** + * Created by haibin + * on 2016/11/4. + */ + +public class QRCodeActivity extends BaseActivity { + @Override + protected int getContentView() { + return 0; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/main/discover/ShakeNewsFragment.java b/app/src/main/java/net/oschina/app/improve/main/discover/ShakeNewsFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..7b4a936f5ded6d727a61cf2ea1c28059d8e86931 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/main/discover/ShakeNewsFragment.java @@ -0,0 +1,134 @@ +package net.oschina.app.improve.main.discover; + +import android.os.Handler; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.google.gson.reflect.TypeToken; + +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.bean.Banner; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.bean.shake.ShakeNews; +import net.oschina.app.util.StringUtils; +import net.oschina.app.util.TDevice; +import net.oschina.app.util.UIHelper; + +import java.lang.reflect.Type; + +/** + * 摇一摇新闻咨询等相关界面实现 + */ +public class ShakeNewsFragment extends BaseSensorFragment { + + private ImageView mImgNews; + private TextView mTxtNewsName, mTxtPubTime; + + public static ShakeNewsFragment newInstance() { + ShakeNewsFragment fragment = new ShakeNewsFragment(); + return fragment; + } + + @Override + protected int getLayoutId() { + return R.layout.fragment_shake_news; + } + + @Override + protected void initWidget(View root) { + super.initWidget(root); + mShakeView = mInflater.inflate(R.layout.view_news, null); + mImgNews = (ImageView) mShakeView.findViewById(R.id.iv_news); + mTxtNewsName = (TextView) mShakeView.findViewById(R.id.tv_news_name); + mTxtPubTime = (TextView) mShakeView.findViewById(R.id.tv_time); + mDelayTime = 1; + mCardView.setVisibility(View.GONE); + mTvState.setText("摇一摇获取资讯"); + } + + @Override + public void onClick(View v) { + if (mBean != null) { + Banner banner = new Banner(); + ShakeNews news = mBean.getResult(); + banner.setId(news.getId()); + banner.setType(news.getType()); + banner.setName(news.getName()); + UIHelper.showBannerDetail(mContext, banner); + } + } + + @Override + public void onShake() { + if (!TDevice.hasInternet()) { + Toast.makeText(mContext, "网络连接失败", Toast.LENGTH_SHORT).show(); + mLoading = false; + return; + } + OSChinaApi.getShakeNews(mHandler); + } + + @Override + protected void initShakeView() { + ShakeNews news = mBean.getResult(); + mCardView.setVisibility(View.VISIBLE); + getImgLoader().load(news.getImg()) + .placeholder(R.mipmap.ic_split_graph) + .into(mImgNews); + mTxtNewsName.setText(news.getName()); + mTxtPubTime.setText(StringUtils.formatSomeAgo(news.getPubDate())); + } + + @Override + protected void onRequestStart() { + super.onRequestStart(); + mTvState.setText("正在搜寻资讯"); + } + + @Override + protected void onTimeProgress() { + if (mContext != null) { + if (mTimeHandler == null) + mTimeHandler = new Handler(); + mLoadingView.setVisibility(View.GONE); + //mTxtTime.setVisibility(View.VISIBLE); + //mTxtTime.setText(String.format("%d秒后可再摇一次", mDelayTime)); + mTimeHandler.postDelayed(new Runnable() { + @Override + public void run() { + if (mTxtTime == null) + return; + mTxtTime.setVisibility(View.VISIBLE); + --mDelayTime; + if (mTxtTime == null) + return; + //mTxtTime.setText(String.format("%d秒后可再摇一次", mDelayTime)); + if (mDelayTime > 0) + mTimeHandler.postDelayed(this, 1000); + else { + mTxtTime.setVisibility(View.INVISIBLE); + mTvState.setVisibility(View.VISIBLE); + mTvState.setText("摇一摇获取资讯"); + mLoading = false; + mDelayTime = 1; + } + } + }, 1000); + } + } + + @Override + protected void onFailure() { + super.onFailure(); + mTvState.setText("很遗憾,你没有摇到资讯,请再试一次"); + } + + @Override + protected Type getType() { + return new TypeToken>() { + }.getType(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/main/discover/ShakePresentActivity.java b/app/src/main/java/net/oschina/app/improve/main/discover/ShakePresentActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..b36e94632b70b5775477030a813e8d0411872ec5 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/main/discover/ShakePresentActivity.java @@ -0,0 +1,99 @@ +package net.oschina.app.improve.main.discover; + +import android.content.Context; +import android.content.Intent; +import android.view.View; +import android.widget.LinearLayout; + +import net.oschina.app.R; +import net.oschina.app.improve.base.activities.BaseBackActivity; + +import butterknife.Bind; +import butterknife.OnClick; + +/** + * 摇一摇活动界面 + */ +public class ShakePresentActivity extends BaseBackActivity implements View.OnClickListener { + + @Bind(R.id.ll_shake_present) + LinearLayout mLayShakePresent; + + @Bind(R.id.ll_shake_news) + LinearLayout mLayShakeNews; + + private ShakePresentFragment mPresentFragment; + private ShakeNewsFragment mNewsFragment; + + private boolean mIsRegisterPresent; + + public static void show(Context context) { + context.startActivity(new Intent(context, ShakePresentActivity.class)); + } + + @Override + protected int getContentView() { + return R.layout.activity_shake_present; + } + + @Override + protected void initWidget() { + super.initWidget(); + mNewsFragment = ShakeNewsFragment.newInstance(); + mPresentFragment = ShakePresentFragment.newInstance(); + addFragment(R.id.fl_content, mNewsFragment); + addFragment(R.id.fl_content, mPresentFragment); + setState(mLayShakePresent, true); + mIsRegisterPresent = true; + } + + @OnClick({R.id.ll_shake_present, R.id.ll_shake_news}) + @Override + public void onClick(View v) { + if (v.getId() == R.id.ll_shake_present) { + addFragment(R.id.fl_content, mPresentFragment); + mNewsFragment.unregisterSensor(); + mPresentFragment.registerSensor(); + setState(mLayShakeNews, false); + setState(mLayShakePresent, true); + mIsRegisterPresent = true; + } else if (v.getId() == R.id.ll_shake_news) { + addFragment(R.id.fl_content, mNewsFragment); + mPresentFragment.unregisterSensor(); + mNewsFragment.registerSensor(); + setState(mLayShakePresent, false); + setState(mLayShakeNews, true); + mIsRegisterPresent = false; + } + } + + @Override + protected void onPause() { + super.onPause(); + mPresentFragment.unregisterSensor(); + mNewsFragment.unregisterSensor(); + } + + @Override + protected void onResume() { + super.onResume(); + if (mIsRegisterPresent) { + mPresentFragment.registerSensor(); + } else { + mNewsFragment.registerSensor(); + } + } + + @Override + public void finish() { + super.finish(); + mPresentFragment.unregisterSensor(); + mNewsFragment.unregisterSensor(); + } + + private void setState(LinearLayout layout, boolean selected) { + for (int i = 0; i < layout.getChildCount(); i++) { + layout.getChildAt(i).setSelected(selected); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/main/discover/ShakePresentFragment.java b/app/src/main/java/net/oschina/app/improve/main/discover/ShakePresentFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..dca6746fef288b86bbdf52410d24e768e7ee8f49 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/main/discover/ShakePresentFragment.java @@ -0,0 +1,166 @@ +package net.oschina.app.improve.main.discover; + +import android.content.Intent; +import android.os.Handler; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.google.gson.reflect.TypeToken; + +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.account.activity.LoginActivity; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.bean.shake.ShakePresent; +import net.oschina.app.util.TDevice; +import net.oschina.app.util.UIHelper; +import net.oschina.common.verify.Verifier; + +import java.lang.reflect.Type; + +/** + * 摇一摇礼品相关实现 + */ +public class ShakePresentFragment extends BaseSensorFragment { + private Button mBtnShakeAgain, mBtnGet; + private ImageView mImgPig; + private TextView mTxtName; + private boolean mCanAgain; + + public static ShakePresentFragment newInstance() { + ShakePresentFragment fragment = new ShakePresentFragment(); + return fragment; + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode == AppCompatActivity.RESULT_OK && requestCode == 1) { + mLoading = false; + } + } + + @Override + protected int getLayoutId() { + return R.layout.fragment_shake_present; + } + + @Override + protected void initWidget(View root) { + super.initWidget(root); + mShakeView = mInflater.inflate(R.layout.view_present, null); + mBtnShakeAgain = (Button) mShakeView.findViewById(R.id.btn_shake_again); + mBtnGet = (Button) mShakeView.findViewById(R.id.btn_get); + mImgPig = (ImageView) mShakeView.findViewById(R.id.iv_pig); + mTxtName = (TextView) mShakeView.findViewById(R.id.tv_name); + mBtnShakeAgain.setOnClickListener(this); + mBtnGet.setOnClickListener(this); + mSpeedThreshold = 70; + mCardView.setVisibility(View.GONE); + mTvState.setText("摇一摇抢礼品"); + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.btn_shake_again: + if (mLoading && mCanAgain) { + mCardView.clearAnimation(); + mCardView.setVisibility(View.GONE); + mCardView.removeAllViews(); + mCanAgain = false; + mLoading = false; + } + break; + case R.id.btn_get: + if (mBean != null) { + UIHelper.showUrlRedirect(mContext, mBean.getResult().getHref()); + } + break; + default: + + break; + } + } + + @Override + public void onShake() { + if (!TDevice.hasInternet()) { + Toast.makeText(mContext, "网络连接失败", Toast.LENGTH_SHORT).show(); + mLoading = false; + return; + } + if (!AccountHelper.isLogin()) { + LoginActivity.show(ShakePresentFragment.this, 1); + Toast.makeText(mContext, "摇礼品需要登陆", Toast.LENGTH_LONG).show(); + return; + } + mCanAgain = false; + String appToken = Verifier.getPrivateToken(getActivity().getApplication()); + long time = System.currentTimeMillis(); + String sign = Verifier.signStringArray(String.valueOf(time), String.valueOf(AccountHelper.getUserId()), + appToken); + OSChinaApi.getShakePresent(time, appToken, sign, mHandler); + } + + @Override + protected void onTimeProgress() { + if (mContext != null) { + if (mTimeHandler == null) + mTimeHandler = new Handler(); + mLoadingView.setVisibility(View.GONE); + if (mBean != null && mBean.getCode() == 251) {//活动进行中,没摇到 + mBtnShakeAgain.setTextColor(0xFFD8D8D8); + mTxtTime.setVisibility((mBean == null || mBean.getResult() == null) ? View.VISIBLE : View.INVISIBLE); + mTxtTime.setText(String.format("%s秒后可再摇一次", mDelayTime)); + mTimeHandler.postDelayed(new Runnable() { + @Override + public void run() { + --mDelayTime; + if (mTxtTime == null) + return; + if (mBean == null || mBean.getResult() == null) { + mTxtTime.setText(String.format("%s秒后可再摇一次", mDelayTime)); + } else { + mBtnShakeAgain.setText(String.format("再摇一次(%s)", mDelayTime)); + } + if (mDelayTime > 0) + mTimeHandler.postDelayed(this, 1000); + else { + mBtnShakeAgain.setText("再摇一次"); + mBtnShakeAgain.setTextColor(0xFF111111); + mTvState.setText("摇一摇抢礼品"); + mCanAgain = true; + mTxtTime.setVisibility(View.INVISIBLE); + mLoading = mBean != null && mBean.getResult() != null; + mDelayTime = 5; + } + } + }, 1000); + } else { + mTvState.setText(mBean != null ? mBean.getMessage() : "很抱歉,出现未知错误"); + mLoading = false; + } + } + } + + @Override + protected void initShakeView() { + ShakePresent present = mBean.getResult(); + mCardView.setVisibility(View.VISIBLE); + getImgLoader().load(present.getPic()).placeholder(R.mipmap.ic_split_graph).into(mImgPig); + mTxtName.setText(present.getName()); + mTvState.setText("恭喜您中奖了"); + } + + @Override + protected Type getType() { + return new TypeToken>() { + }.getType(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/main/nav/NavFragment.java b/app/src/main/java/net/oschina/app/improve/main/nav/NavFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..ae391b90af87166cddd86890e9f35a20e268f5eb --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/main/nav/NavFragment.java @@ -0,0 +1,225 @@ +package net.oschina.app.improve.main.nav; + + +import android.content.Context; +import android.graphics.RectF; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; +import android.graphics.drawable.ShapeDrawable; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; +import android.view.View; + +import net.oschina.app.R; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.base.fragments.BaseFragment; +import net.oschina.app.improve.main.tabs.DynamicTabFragment; +import net.oschina.app.improve.main.tabs.ExploreFragment; +import net.oschina.app.improve.main.tabs.TweetViewPagerFragment; +import net.oschina.app.improve.notice.NoticeBean; +import net.oschina.app.improve.notice.NoticeManager; +import net.oschina.app.improve.tweet.activities.TweetPublishActivity; +import net.oschina.app.improve.user.activities.UserFansActivity; +import net.oschina.app.improve.user.activities.UserMessageActivity; +import net.oschina.app.improve.user.fragments.UserInfoFragment; +import net.qiujuer.genius.ui.drawable.shape.BorderShape; + +import java.util.List; + +import butterknife.Bind; +import butterknife.OnClick; + +/** + * A simple {@link Fragment} subclass. + */ +public class NavFragment extends BaseFragment implements View.OnClickListener, NoticeManager.NoticeNotify { + @Bind(R.id.nav_item_news) + NavigationButton mNavNews; + @Bind(R.id.nav_item_tweet) + NavigationButton mNavTweet; + @Bind(R.id.nav_item_explore) + NavigationButton mNavExplore; + @Bind(R.id.nav_item_me) + NavigationButton mNavMe; + + private Context mContext; + private int mContainerId; + private FragmentManager mFragmentManager; + private NavigationButton mCurrentNavButton; + private OnNavigationReselectListener mOnNavigationReselectListener; + + public NavFragment() { + // Required empty public constructor + } + + @Override + protected int getLayoutId() { + return R.layout.fragment_nav; + } + + @SuppressWarnings("deprecation") + @Override + protected void initWidget(View root) { + super.initWidget(root); + + ShapeDrawable lineDrawable = new ShapeDrawable(new BorderShape(new RectF(0, 1, 0, 0))); + lineDrawable.getPaint().setColor(getResources().getColor(R.color.list_divider_color)); + LayerDrawable layerDrawable = new LayerDrawable(new Drawable[]{ + new ColorDrawable(getResources().getColor(R.color.white)), + lineDrawable + }); + root.setBackgroundDrawable(layerDrawable); + + mNavNews.init(R.drawable.tab_icon_new, + R.string.main_tab_name_news, + DynamicTabFragment.class); + + mNavTweet.init(R.drawable.tab_icon_tweet, + R.string.main_tab_name_tweet, + TweetViewPagerFragment.class); + + mNavExplore.init(R.drawable.tab_icon_explore, + R.string.main_tab_name_explore, + ExploreFragment.class); + + mNavMe.init(R.drawable.tab_icon_me, + R.string.main_tab_name_my, + UserInfoFragment.class); + + } + + @OnClick({R.id.nav_item_news, R.id.nav_item_tweet, + R.id.nav_item_explore, R.id.nav_item_me, + R.id.nav_item_tweet_pub}) + @Override + public void onClick(View v) { + if (v instanceof NavigationButton) { + NavigationButton nav = (NavigationButton) v; + doSelect(nav); + } else if (v.getId() == R.id.nav_item_tweet_pub) { + TweetPublishActivity.show(getContext(), mRoot.findViewById(R.id.nav_item_tweet_pub)); + } + } + + public void setup(Context context, FragmentManager fragmentManager, int contentId, OnNavigationReselectListener listener) { + mContext = context; + mFragmentManager = fragmentManager; + mContainerId = contentId; + mOnNavigationReselectListener = listener; + + // do clear + clearOldFragment(); + // do select first + doSelect(mNavNews); + } + + public void select(int index) { + if (mNavMe != null) + doSelect(mNavMe); + } + + @SuppressWarnings("RestrictedApi") + private void clearOldFragment() { + FragmentTransaction transaction = mFragmentManager.beginTransaction(); + List fragments = mFragmentManager.getFragments(); + if (transaction == null || fragments == null || fragments.size() == 0) + return; + boolean doCommit = false; + for (Fragment fragment : fragments) { + if (fragment != this) { + transaction.remove(fragment); + doCommit = true; + } + } + if (doCommit) + transaction.commitNow(); + } + + private void doSelect(NavigationButton newNavButton) { + // If the new navigation is me info fragment, we intercept it + /* + if (newNavButton == mNavMe) { + if (interceptMessageSkip()) + return; + } + */ + + NavigationButton oldNavButton = null; + if (mCurrentNavButton != null) { + oldNavButton = mCurrentNavButton; + if (oldNavButton == newNavButton) { + onReselect(oldNavButton); + return; + } + oldNavButton.setSelected(false); + } + newNavButton.setSelected(true); + doTabChanged(oldNavButton, newNavButton); + mCurrentNavButton = newNavButton; + } + + private void doTabChanged(NavigationButton oldNavButton, NavigationButton newNavButton) { + FragmentTransaction ft = mFragmentManager.beginTransaction(); + if (oldNavButton != null) { + if (oldNavButton.getFragment() != null) { + ft.detach(oldNavButton.getFragment()); + } + } + if (newNavButton != null) { + if (newNavButton.getFragment() == null) { + Fragment fragment = Fragment.instantiate(mContext, + newNavButton.getClx().getName(), null); + ft.add(mContainerId, fragment, newNavButton.getTag()); + newNavButton.setFragment(fragment); + } else { + ft.attach(newNavButton.getFragment()); + } + } + ft.commit(); + } + + /** + * 拦截底部点击,当点击个人按钮时进行消息跳转 + */ + private boolean interceptMessageSkip() { + NoticeBean bean = NoticeManager.getNotice(); + if (bean.getAllCount() > 0) { + if (bean.getLetter() + bean.getMention() + bean.getReview() > 0) + UserMessageActivity.show(getActivity()); + else + UserFansActivity.show(getActivity(), AccountHelper.getUserId()); + return true; + } + return false; + } + + private void onReselect(NavigationButton navigationButton) { + OnNavigationReselectListener listener = mOnNavigationReselectListener; + if (listener != null) { + listener.onReselect(navigationButton); + } + } + + @Override + public void onNoticeArrived(NoticeBean bean) { + mNavMe.showRedDot(bean.getAllCount()); + } + + public interface OnNavigationReselectListener { + void onReselect(NavigationButton navigationButton); + } + + @Override + public void onDestroy() { + super.onDestroy(); + NoticeManager.unBindNotify(this); + } + + @Override + protected void initData() { + super.initData(); + NoticeManager.bindNotify(this); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/main/nav/NavigationButton.java b/app/src/main/java/net/oschina/app/improve/main/nav/NavigationButton.java new file mode 100644 index 0000000000000000000000000000000000000000..df4a16801f503e5b41796119607050752f903364 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/main/nav/NavigationButton.java @@ -0,0 +1,94 @@ +package net.oschina.app.improve.main.nav; + +import android.content.Context; +import android.os.Build; +import android.support.annotation.DrawableRes; +import android.support.annotation.RequiresApi; +import android.support.annotation.StringRes; +import android.support.v4.app.Fragment; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import net.oschina.app.R; + +/** + * Created by JuQiu + * on 16/8/18. + */ +public class NavigationButton extends FrameLayout { + private Fragment mFragment = null; + private Class mClx; + private ImageView mIconView; + private TextView mTitleView; + private TextView mDot; + private String mTag; + + public NavigationButton(Context context) { + super(context); + init(); + } + + public NavigationButton(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public NavigationButton(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + public NavigationButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + init(); + } + + private void init() { + LayoutInflater inflater = LayoutInflater.from(getContext()); + inflater.inflate(R.layout.layout_nav_item, this, true); + + mIconView = (ImageView) findViewById(R.id.nav_iv_icon); + mTitleView = (TextView) findViewById(R.id.nav_tv_title); + mDot = (TextView) findViewById(R.id.nav_tv_dot); + } + + public void setSelected(boolean selected) { + super.setSelected(selected); + mIconView.setSelected(selected); + mTitleView.setSelected(selected); + } + + public void showRedDot(int count) { + mDot.setVisibility(count > 0 ? VISIBLE : GONE); + mDot.setText(String.valueOf(count)); + } + + public void init(@DrawableRes int resId, @StringRes int strId, Class clx) { + mIconView.setImageResource(resId); + mTitleView.setText(strId); + mClx = clx; + mTag = mClx.getName(); + } + + public Class getClx() { + return mClx; + } + + public Fragment getFragment() { + return mFragment; + } + + public void setFragment(Fragment fragment) { + this.mFragment = fragment; + } + + public String getTag() { + return mTag; + } + + +} diff --git a/app/src/main/java/net/oschina/app/improve/main/subscription/BlogSubAdapter.java b/app/src/main/java/net/oschina/app/improve/main/subscription/BlogSubAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..abc9e8c0ce88e00d4741803c1191f625fbf4d865 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/main/subscription/BlogSubAdapter.java @@ -0,0 +1,158 @@ +package net.oschina.app.improve.main.subscription; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.drawable.Drawable; +import android.support.v7.widget.RecyclerView; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.TextUtils; +import android.text.style.ImageSpan; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import android.widget.TextView; + +import net.oschina.app.OSCApplication; +import net.oschina.app.R; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.bean.SubBean; +import net.oschina.app.improve.bean.simple.Author; +import net.oschina.app.util.StringUtils; +import net.qiujuer.genius.ui.compat.UiCompat; + +/** + * 新板博客栏目 + * Created by haibin + * on 2016/10/26. + */ + +public class BlogSubAdapter extends BaseRecyclerAdapter implements BaseRecyclerAdapter.OnLoadingHeaderCallBack { + + private OSCApplication.ReadState mReadState; + + public BlogSubAdapter(Context context, int mode) { + super(context, mode); + mReadState = OSCApplication.getReadState("sub_list"); + setOnLoadingHeaderCallBack(this); + } + + @Override + public RecyclerView.ViewHolder onCreateHeaderHolder(ViewGroup parent) { + return new HeaderViewHolder(mHeaderView); + } + + @Override + public void onBindHeaderHolder(RecyclerView.ViewHolder holder, int position) { + } + + @Override + protected RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type) { + return new BlogViewHolder(mInflater.inflate(R.layout.item_list_sub_blog, parent, false)); + } + + @Override + protected void onBindDefaultViewHolder(RecyclerView.ViewHolder holder, SubBean item, int position) { + BlogViewHolder vh = (BlogViewHolder) holder; + + TextView title = vh.tv_title; + TextView content = vh.tv_description; + TextView see = vh.tv_view; + TextView answer = vh.tv_comment_count; + + String text = ""; + SpannableStringBuilder spannable = new SpannableStringBuilder(text); + + Resources resources = mContext.getResources(); + + boolean isToday = StringUtils.isSameDay(mSystemTime, item.getPubDate()); + if (isToday) { + spannable.append("[icon] "); + Drawable originate = resources.getDrawable(R.mipmap.ic_label_today); + if (originate != null) { + originate.setBounds(0, 0, originate.getIntrinsicWidth(), originate.getIntrinsicHeight()); + } + ImageSpan imageSpan = new ImageSpan(originate, ImageSpan.ALIGN_BOTTOM); + spannable.setSpan(imageSpan, 0, 6, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + } + + if (item.isOriginal()) { + spannable.append("[icon] "); + Drawable originate = resources.getDrawable(R.mipmap.ic_label_originate); + if (originate != null) { + originate.setBounds(0, 0, originate.getIntrinsicWidth(), originate.getIntrinsicHeight()); + } + ImageSpan imageSpan = new ImageSpan(originate, ImageSpan.ALIGN_BOTTOM); + spannable.setSpan(imageSpan, isToday ? 7 : 0, isToday ? 13 : 6, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + } else { + spannable.append("[icon] "); + Drawable originate = resources.getDrawable(R.mipmap.ic_label_reprint); + if (originate != null) { + originate.setBounds(0, 0, originate.getIntrinsicWidth(), originate.getIntrinsicHeight()); + } + ImageSpan imageSpan = new ImageSpan(originate, ImageSpan.ALIGN_BOTTOM); + spannable.setSpan(imageSpan, isToday ? 7 : 0, isToday ? 13 : 6, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + } + + if (item.isRecommend()) { + spannable.append("[icon] "); + Drawable recommend = resources.getDrawable(R.mipmap.ic_label_recommend); + if (recommend != null) { + recommend.setBounds(0, 0, recommend.getIntrinsicWidth(), recommend.getIntrinsicHeight()); + } + ImageSpan imageSpan = new ImageSpan(recommend, ImageSpan.ALIGN_BOTTOM); + spannable.setSpan(imageSpan, isToday ? 14 : 7, isToday ? 20 : 13, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + } + + title.setText(spannable.append(item.getTitle())); + + String body = item.getBody(); + if (!TextUtils.isEmpty(body)) { + body = body.trim(); + if (!TextUtils.isEmpty(body)) { + content.setText(body); + content.setVisibility(View.VISIBLE); + } else { + content.setVisibility(View.GONE); + } + } + + if (mReadState.already(item.getKey())) { + title.setTextColor(UiCompat.getColor(resources, R.color.text_desc_color)); + content.setTextColor(UiCompat.getColor(resources, R.color.text_secondary_color)); + } else { + title.setTextColor(UiCompat.getColor(resources, R.color.text_title_color)); + content.setTextColor(UiCompat.getColor(resources, R.color.text_desc_color)); + } + + Author author = item.getAuthor(); + String authorName; + if (author != null && !TextUtils.isEmpty(authorName = author.getName())) { + authorName = authorName.trim(); + vh.tv_time.setText(String.format("@%s %s", + (authorName.length() > 9 ? authorName.substring(0, 9) : authorName), + StringUtils.formatSomeAgo(item.getPubDate().trim()))); + } else { + vh.tv_time.setText(StringUtils.formatSomeAgo(item.getPubDate().trim())); + } + + + see.setText(String.valueOf(item.getStatistics().getView())); + answer.setText(String.valueOf(item.getStatistics().getComment())); + } + + private static class BlogViewHolder extends RecyclerView.ViewHolder { + TextView tv_title, tv_description, tv_time, tv_comment_count, tv_view; + LinearLayout ll_title; + + public BlogViewHolder(View itemView) { + super(itemView); + tv_title = (TextView) itemView.findViewById(R.id.tv_title); + tv_description = (TextView) itemView.findViewById(R.id.tv_description); + tv_time = (TextView) itemView.findViewById(R.id.tv_time); + tv_comment_count = (TextView) itemView.findViewById(R.id.tv_info_comment); + tv_view = (TextView) itemView.findViewById(R.id.tv_info_view); + ll_title = (LinearLayout) itemView.findViewById(R.id.ll_title); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/main/subscription/EventSubAdapter.java b/app/src/main/java/net/oschina/app/improve/main/subscription/EventSubAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..671a40f15af70209b2f19fd9c63c44007ba9ae83 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/main/subscription/EventSubAdapter.java @@ -0,0 +1,136 @@ +package net.oschina.app.improve.main.subscription; + +import android.content.res.Resources; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import net.oschina.app.OSCApplication; +import net.oschina.app.R; +import net.oschina.app.improve.base.adapter.BaseGeneralRecyclerAdapter; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.bean.Event; +import net.oschina.app.improve.bean.SubBean; +import net.oschina.app.util.StringUtils; +import net.qiujuer.genius.ui.compat.UiCompat; + +import java.util.Map; + +/** + * 新版活动栏目 + * Created by haibin + * on 2016/10/27. + */ + +public class EventSubAdapter extends BaseGeneralRecyclerAdapter implements BaseRecyclerAdapter.OnLoadingHeaderCallBack { + private OSCApplication.ReadState mReadState; + + public EventSubAdapter(Callback callback, int mode) { + super(callback, mode); + mReadState = OSCApplication.getReadState("sub_list"); + setOnLoadingHeaderCallBack(this); + } + + @Override + public RecyclerView.ViewHolder onCreateHeaderHolder(ViewGroup parent) { + return new HeaderViewHolder(mHeaderView); + } + + @Override + public void onBindHeaderHolder(RecyclerView.ViewHolder holder, int position) { + + } + + @Override + protected RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type) { + return new EventViewHolder(mInflater.inflate(R.layout.item_list_sub_event, parent, false)); + } + + @Override + protected void onBindDefaultViewHolder(RecyclerView.ViewHolder holder, SubBean item, int position) { + EventViewHolder vh = (EventViewHolder) holder; + vh.tv_event_title.setText(item.getTitle()); + SubBean.Image image = item.getImage(); + if (image != null) { + mCallBack.getImgLoader() + .load(image.getHref() != null && image.getHref().length > 0 ? image.getHref()[0] : null) + .placeholder(R.drawable.bg_normal) + .into(vh.iv_event); + } else { + vh.iv_event.setImageResource(R.drawable.bg_normal); + } + + Resources resources = mContext.getResources(); + + Map extras = item.getExtra(); + if (extras != null) { + vh.tv_event_pub_date.setText(StringUtils.getDateString(extras.get("eventStartDate").toString())); + vh.tv_event_member.setText(Double.valueOf(extras.get("eventApplyCount").toString()).intValue() + "人参与"); + + switch (Double.valueOf(extras.get("eventStatus").toString()).intValue()) { + case Event.STATUS_END: + setText(vh.tv_event_state, R.string.event_status_end, R.drawable.bg_event_end, 0x1a000000); + setTextColor(vh.tv_event_title, UiCompat.getColor(resources, R.color.light_gray)); + break; + case Event.STATUS_ING: + setText(vh.tv_event_state, R.string.event_status_ing, R.drawable.bg_event_ing, 0xFF24cf5f); + break; + case Event.STATUS_SING_UP: + setText(vh.tv_event_state, R.string.event_status_sing_up, R.drawable.bg_event_end, 0x1a000000); + setTextColor(vh.tv_event_title, UiCompat.getColor(resources, R.color.light_gray)); + break; + } + int typeStr = R.string.oscsite; + switch (Double.valueOf(extras.get("eventType").toString()).intValue()) { + case Event.EVENT_TYPE_OSC: + typeStr = R.string.event_type_osc; + break; + case Event.EVENT_TYPE_TEC: + typeStr = R.string.event_type_tec; + break; + case Event.EVENT_TYPE_OTHER: + typeStr = R.string.event_type_other; + break; + case Event.EVENT_TYPE_OUTSIDE: + typeStr = R.string.event_type_outside; + break; + } + vh.tv_event_type.setText(typeStr); + } + + vh.tv_event_title.setTextColor(UiCompat.getColor(resources, + mReadState.already(item.getKey()) + ? R.color.text_desc_color : R.color.text_title_color)); + + } + + private void setText(TextView tv, int textRes, int bgRes, int textColor) { + tv.setText(textRes); + tv.setVisibility(View.VISIBLE); + tv.setBackgroundResource(bgRes); + tv.setTextColor(textColor); + } + + private void setTextColor(TextView tv, int textColor) { + tv.setTextColor(textColor); + tv.setVisibility(View.VISIBLE); + } + + private static class EventViewHolder extends RecyclerView.ViewHolder { + TextView tv_event_title, tv_description, tv_event_pub_date, tv_event_member, tv_event_state, tv_event_type; + ImageView iv_event; + + public EventViewHolder(View itemView) { + super(itemView); + tv_event_title = (TextView) itemView.findViewById(R.id.tv_event_title); + tv_event_state = (TextView) itemView.findViewById(R.id.tv_event_state); + tv_event_type = (TextView) itemView.findViewById(R.id.tv_event_type); + tv_description = (TextView) itemView.findViewById(R.id.tv_description); + tv_event_pub_date = (TextView) itemView.findViewById(R.id.tv_event_pub_date); + tv_event_member = (TextView) itemView.findViewById(R.id.tv_event_member); + iv_event = (ImageView) itemView.findViewById(R.id.iv_event); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/main/subscription/NewsSubAdapter.java b/app/src/main/java/net/oschina/app/improve/main/subscription/NewsSubAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..22e892f34dcbfc2dc2974d48e95b93cb7b2363b1 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/main/subscription/NewsSubAdapter.java @@ -0,0 +1,128 @@ +package net.oschina.app.improve.main.subscription; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.drawable.Drawable; +import android.support.v7.widget.RecyclerView; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.TextUtils; +import android.text.style.ImageSpan; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import android.widget.TextView; + +import net.oschina.app.OSCApplication; +import net.oschina.app.R; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.bean.SubBean; +import net.oschina.app.improve.bean.SubTab; +import net.oschina.app.improve.bean.simple.Author; +import net.oschina.app.util.StringUtils; +import net.qiujuer.genius.ui.compat.UiCompat; + +/** + * 新版新闻订阅栏目 + * Created by haibin + * on 2016/10/26. + */ + +public class NewsSubAdapter extends BaseRecyclerAdapter implements BaseRecyclerAdapter.OnLoadingHeaderCallBack { + private OSCApplication.ReadState mReadState; + private SubTab mTab; + + public NewsSubAdapter(Context context, int mode) { + super(context, mode); + mReadState = OSCApplication.getReadState("sub_list"); + setOnLoadingHeaderCallBack(this); + } + + public void setTab(SubTab tab) { + this.mTab = tab; + } + + @Override + public RecyclerView.ViewHolder onCreateHeaderHolder(ViewGroup parent) { + return new HeaderViewHolder(mHeaderView); + } + + @Override + public void onBindHeaderHolder(RecyclerView.ViewHolder holder, int position) { + + } + + @Override + protected RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type) { + return new NewsViewHolder(mInflater.inflate(R.layout.item_list_sub_news, parent, false)); + } + + @Override + protected void onBindDefaultViewHolder(RecyclerView.ViewHolder holder, SubBean item, int position) { + NewsViewHolder vh = (NewsViewHolder) holder; + + Resources resources = mContext.getResources(); + + if (mReadState.already(item.getKey())) { + vh.tv_title.setTextColor(UiCompat.getColor(resources, R.color.text_desc_color)); + vh.tv_description.setTextColor(UiCompat.getColor(resources, R.color.text_secondary_color)); + } else { + vh.tv_title.setTextColor(UiCompat.getColor(resources, R.color.text_title_color)); + vh.tv_description.setTextColor(UiCompat.getColor(resources, R.color.text_desc_color)); + } + + vh.tv_description.setText(item.getBody()); + + Author author = item.getAuthor(); + String authorName; + if (author != null && !TextUtils.isEmpty(authorName = author.getName())) { + authorName = authorName.trim(); + vh.tv_time.setText(String.format("@%s %s", + (authorName.length() > 9 ? authorName.substring(0, 9) : authorName), + StringUtils.formatSomeAgo(item.getPubDate().trim()))); + } else { + vh.tv_time.setText(StringUtils.formatSomeAgo(item.getPubDate().trim())); + } + + if (StringUtils.isSameDay(mSystemTime, item.getPubDate()) && mTab.getSubtype() != 2 && item.getType() != 7) { + + String text = "[icon] " + item.getTitle(); + Drawable drawable = resources.getDrawable(R.mipmap.ic_label_today); + drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); + ImageSpan imageSpan = new ImageSpan(drawable, ImageSpan.ALIGN_BOTTOM); + + SpannableString spannable = new SpannableString(text); + spannable.setSpan(imageSpan, 0, 6, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + vh.tv_title.setText(spannable); + vh.tv_title.setTextSize(16.0f); + } else { + vh.tv_title.setText(item.getTitle()); + } + if (item.getType() == 0) { + vh.ll_info.setVisibility(View.GONE); + } else { + vh.ll_info.setVisibility(View.VISIBLE); + vh.tv_comment_count.setText(String.valueOf(item.getStatistics().getComment())); + vh.tv_view_count.setText(String.valueOf(item.getStatistics().getView())); + } + } + + private static class NewsViewHolder extends RecyclerView.ViewHolder { + TextView tv_title, tv_description, tv_time, tv_comment_count, tv_view_count; + LinearLayout ll_title, ll_info; + + public NewsViewHolder(View itemView) { + super(itemView); + tv_title = (TextView) itemView.findViewById(R.id.tv_title); + tv_description = (TextView) itemView.findViewById(R.id.tv_description); + tv_time = (TextView) itemView.findViewById(R.id.tv_time); + ll_title = (LinearLayout) itemView.findViewById(R.id.ll_title); + + ll_info = (LinearLayout) itemView.findViewById(R.id.lay_info); + tv_comment_count = (TextView) ll_info.findViewById(R.id.tv_info_comment); + tv_view_count = (TextView) ll_info.findViewById(R.id.tv_info_view); + tv_view_count.setVisibility(View.GONE); + ll_info.findViewById(R.id.iv_info_view).setVisibility(View.GONE); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/main/subscription/QuestionSubAdapter.java b/app/src/main/java/net/oschina/app/improve/main/subscription/QuestionSubAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..77df3830fbcd39eaaf04bef34bc6b2612f727a55 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/main/subscription/QuestionSubAdapter.java @@ -0,0 +1,103 @@ +package net.oschina.app.improve.main.subscription; + +import android.content.res.Resources; +import android.support.v7.widget.RecyclerView; +import android.text.TextUtils; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import net.oschina.app.OSCApplication; +import net.oschina.app.R; +import net.oschina.app.improve.base.adapter.BaseGeneralRecyclerAdapter; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.bean.SubBean; +import net.oschina.app.improve.bean.simple.Author; +import net.oschina.app.util.StringUtils; +import net.qiujuer.genius.ui.compat.UiCompat; + +import de.hdodenhof.circleimageview.CircleImageView; + +/** + * 新版栏目问答 + * Created by haibin + * on 2016/10/27. + */ + +public class QuestionSubAdapter extends BaseGeneralRecyclerAdapter implements BaseRecyclerAdapter.OnLoadingHeaderCallBack { + private OSCApplication.ReadState mReadState; + + public QuestionSubAdapter(Callback callback, int mode) { + super(callback, mode); + mReadState = OSCApplication.getReadState("sub_list"); + setOnLoadingHeaderCallBack(this); + } + + @Override + public RecyclerView.ViewHolder onCreateHeaderHolder(ViewGroup parent) { + return new HeaderViewHolder(mHeaderView); + } + + @Override + public void onBindHeaderHolder(RecyclerView.ViewHolder holder, int position) { + + } + + @Override + protected RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type) { + return new QuestionViewHolder(mInflater.inflate(R.layout.item_list_sub_question, parent, false)); + } + + @Override + protected void onBindDefaultViewHolder(RecyclerView.ViewHolder holder, SubBean item, int position) { + QuestionViewHolder vh = (QuestionViewHolder) holder; + + Author author = item.getAuthor(); + + mCallBack.getImgLoader() + .load(author != null ? author.getPortrait() : "") + .asBitmap().placeholder(R.mipmap.widget_dface) + .into(vh.iv_question); + + vh.tv_question_title.setText(item.getTitle()); + vh.tv_question_content.setText(item.getBody()); + + Resources resources = mContext.getResources(); + + if (mReadState.already(item.getKey())) { + vh.tv_question_title.setTextColor(UiCompat.getColor(resources, R.color.text_desc_color)); + vh.tv_question_content.setTextColor(UiCompat.getColor(resources, R.color.text_secondary_color)); + } else { + vh.tv_question_title.setTextColor(UiCompat.getColor(resources, R.color.text_title_color)); + vh.tv_question_content.setTextColor(UiCompat.getColor(resources, R.color.text_desc_color)); + } + + String authorName; + if (author != null && !TextUtils.isEmpty(authorName = author.getName())) { + authorName = authorName.trim(); + vh.tv_time.setText(String.format("@%s %s", + (authorName.length() > 9 ? authorName.substring(0, 9) : authorName), + StringUtils.formatSomeAgo(item.getPubDate().trim()))); + } else { + vh.tv_time.setText(StringUtils.formatSomeAgo(item.getPubDate().trim())); + } + + vh.tv_view.setText(String.valueOf(item.getStatistics().getView())); + vh.tv_comment_count.setText(String.valueOf(item.getStatistics().getComment())); + } + + private static class QuestionViewHolder extends RecyclerView.ViewHolder { + TextView tv_question_title, tv_question_content, tv_time, tv_comment_count, tv_view; + CircleImageView iv_question; + + public QuestionViewHolder(View itemView) { + super(itemView); + tv_question_title = (TextView) itemView.findViewById(R.id.tv_question_title); + tv_question_content = (TextView) itemView.findViewById(R.id.tv_question_content); + tv_time = (TextView) itemView.findViewById(R.id.tv_time); + tv_comment_count = (TextView) itemView.findViewById(R.id.tv_info_comment); + tv_view = (TextView) itemView.findViewById(R.id.tv_info_view); + iv_question = (CircleImageView) itemView.findViewById(R.id.iv_question); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/main/subscription/SubFragment.java b/app/src/main/java/net/oschina/app/improve/main/subscription/SubFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..32eff3ff446f40bd431755f5ed66d4884fadec3f --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/main/subscription/SubFragment.java @@ -0,0 +1,145 @@ +package net.oschina.app.improve.main.subscription; + +import android.content.Context; +import android.os.Bundle; + +import com.google.gson.reflect.TypeToken; + +import net.oschina.app.AppConfig; +import net.oschina.app.OSCApplication; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.base.fragments.BaseGeneralRecyclerFragment; +import net.oschina.app.improve.bean.News; +import net.oschina.app.improve.bean.SubBean; +import net.oschina.app.improve.bean.SubTab; +import net.oschina.app.improve.bean.base.PageBean; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.detail.activities.BlogDetailActivity; +import net.oschina.app.improve.detail.activities.EventDetailActivity; +import net.oschina.app.improve.detail.activities.NewsDetailActivity; +import net.oschina.app.improve.detail.activities.QuestionDetailActivity; +import net.oschina.app.improve.detail.activities.SoftwareDetailActivity; +import net.oschina.app.improve.detail.activities.TranslateDetailActivity; +import net.oschina.app.improve.widget.banner.EventHeaderView; +import net.oschina.app.improve.widget.banner.HeaderView; +import net.oschina.app.improve.widget.banner.NewsHeaderView; +import net.oschina.app.util.UIHelper; + +import java.lang.reflect.Type; + +/** + * Created by haibin + * on 2016/10/26. + */ + +public class SubFragment extends BaseGeneralRecyclerFragment { + private SubTab mTab; + private HeaderView mHeaderView; + private OSCApplication.ReadState mReadState; + + public static SubFragment newInstance(Context context, SubTab subTab) { + SubFragment fragment = new SubFragment(); + Bundle bundle = new Bundle(); + bundle.putSerializable("sub_tab", subTab); + fragment.setArguments(bundle); + return fragment; + } + + @Override + protected void initBundle(Bundle bundle) { + super.initBundle(bundle); + mTab = (SubTab) bundle.getSerializable("sub_tab"); + CACHE_NAME = mTab.getToken(); + } + + @Override + public void initData() { + mReadState = OSCApplication.getReadState("sub_list"); + if (mTab.getBanner() != null) { + mHeaderView = mTab.getBanner().getCatalog() == SubTab.BANNER_CATEGORY_NEWS ? + new NewsHeaderView(mContext, getImgLoader(), mTab.getBanner().getHref(), mTab.getToken() + "banner" + mTab.getType()) : + new EventHeaderView(mContext, getImgLoader(), mTab.getBanner().getHref(), mTab.getToken() + "banner" + mTab.getType()); + } + super.initData(); + mAdapter.setHeaderView(mHeaderView); + mAdapter.setSystemTime(AppConfig.getAppConfig(getActivity()).get("system_time")); + if (mAdapter instanceof NewsSubAdapter) { + ((NewsSubAdapter) mAdapter).setTab(mTab); + } + } + + @Override + public void onItemClick(int position, long itemId) { + SubBean sub = mAdapter.getItem(position); + if (sub == null) + return; + switch (sub.getType()) { + case News.TYPE_SOFTWARE: + SoftwareDetailActivity.show(mContext, sub.getId()); + break; + case News.TYPE_QUESTION: + QuestionDetailActivity.show(mContext, sub.getId()); + break; + case News.TYPE_BLOG: + BlogDetailActivity.show(mContext, sub.getId()); + break; + case News.TYPE_TRANSLATE: + TranslateDetailActivity.show(mContext, sub.getId()); + break; + case News.TYPE_EVENT: + EventDetailActivity.show(mContext, sub.getId()); + break; + case News.TYPE_NEWS: + NewsDetailActivity.show(mContext, sub.getId()); + break; + default: + UIHelper.showUrlRedirect(mContext, sub.getHref()); + break; + } + + mReadState.put(sub.getKey()); + mAdapter.updateItem(position); + } + + @Override + public void onRefreshing() { + super.onRefreshing(); + if (mHeaderView != null) + mHeaderView.requestBanner(); + } + + @Override + protected void requestData() { + OSChinaApi.getSubscription(mTab.getHref(), isRefreshing ? null : mBean.getNextPageToken(), mHandler); + } + + @Override + protected void setListData(ResultBean> resultBean) { + super.setListData(resultBean); + mAdapter.setSystemTime(resultBean.getTime()); + } + + @Override + protected BaseRecyclerAdapter getRecyclerAdapter() { + int mode = mHeaderView != null ? BaseRecyclerAdapter.BOTH_HEADER_FOOTER : BaseRecyclerAdapter.ONLY_FOOTER; + if (mTab.getType() == News.TYPE_BLOG) + return new BlogSubAdapter(getActivity(), mode); + else if (mTab.getType() == News.TYPE_EVENT) + return new EventSubAdapter(this, mode); + else if (mTab.getType() == News.TYPE_QUESTION) + return new QuestionSubAdapter(this, mode); + return new NewsSubAdapter(getActivity(), mode); + } + + @Override + protected Type getType() { + return new TypeToken>>() { + }.getType(); + } + + @Override + protected Class getCacheClass() { + return SubBean.class; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/main/tabs/DynamicTabFragment.java b/app/src/main/java/net/oschina/app/improve/main/tabs/DynamicTabFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..3e9943d2be616a332ce7057cde0305c26c63781e --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/main/tabs/DynamicTabFragment.java @@ -0,0 +1,349 @@ +package net.oschina.app.improve.main.tabs; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.content.Context; +import android.os.Handler; +import android.support.design.widget.TabLayout; +import android.support.v4.app.Fragment; +import android.support.v4.view.PagerAdapter; +import android.support.v4.view.ViewPager; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewPropertyAnimator; +import android.widget.ImageView; + +import com.google.gson.reflect.TypeToken; + +import net.oschina.app.AppContext; +import net.oschina.app.R; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.base.fragments.BaseTitleFragment; +import net.oschina.app.improve.bean.SubTab; +import net.oschina.app.improve.main.MainActivity; +import net.oschina.app.improve.main.subscription.SubFragment; +import net.oschina.app.improve.search.activities.SearchActivity; +import net.oschina.app.improve.widget.FragmentPagerAdapter; +import net.oschina.app.improve.widget.TabPickerView; +import net.oschina.app.interf.OnTabReselectListener; +import net.oschina.app.util.TDevice; +import net.oschina.common.utils.StreamUtil; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.util.ArrayList; +import java.util.List; + +import butterknife.Bind; +import butterknife.OnClick; + +/** + * 动态栏目Fragment + * Created by thanatosx on 16/10/26. + */ + +public class DynamicTabFragment extends BaseTitleFragment implements OnTabReselectListener { + + @Bind(R.id.layout_tab) + TabLayout mLayoutTab; + @Bind(R.id.view_tab_picker) + TabPickerView mViewTabPicker; + @Bind(R.id.view_pager) + ViewPager mViewPager; + @Bind(R.id.iv_arrow_down) + ImageView mViewArrowDown; + + private MainActivity activity; + private Fragment mCurFragment; + private FragmentPagerAdapter mAdapter; + private static TabPickerView.TabPickerDataManager mTabPickerDataManager; + List tabs; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + activity = (MainActivity) context; + activity.addOnTurnBackListener(new MainActivity.TurnBackListener() { + @Override + public boolean onTurnBack() { + return mViewTabPicker != null && mViewTabPicker.onTurnBack(); + } + }); + } + + public static TabPickerView.TabPickerDataManager initTabPickerManager() { + if (mTabPickerDataManager == null) { + mTabPickerDataManager = new TabPickerView.TabPickerDataManager() { + @Override + public List setupActiveDataSet() { + FileReader reader = null; + try { + File file = AppContext.getInstance().getFileStreamPath("sub_tab_active.json"); + if (!file.exists()) return null; + reader = new FileReader(file); + return AppOperator.getGson().fromJson(reader, + new TypeToken>() { + }.getType()); + } catch (IOException e) { + e.printStackTrace(); + } finally { + StreamUtil.close(reader); + } + return null; + } + + @Override + public List setupOriginalDataSet() { + InputStreamReader reader = null; + try { + reader = new InputStreamReader( + AppContext.getInstance().getAssets().open("sub_tab_original.json") + , "UTF-8"); + return AppOperator.getGson().>fromJson(reader, + new TypeToken>() { + }.getType()); + } catch (IOException e) { + e.printStackTrace(); + } finally { + StreamUtil.close(reader); + } + return null; + } + + @Override + public void restoreActiveDataSet(List mActiveDataSet) { + OutputStreamWriter writer = null; + try { + writer = new OutputStreamWriter( + AppContext.getInstance().openFileOutput( + "sub_tab_active.json", Context.MODE_PRIVATE) + , "UTF-8"); + AppOperator.getGson().toJson(mActiveDataSet, writer); + AppContext.set("TabsMask", TDevice.getVersionCode()); + } catch (Exception e) { + e.printStackTrace(); + } finally { + StreamUtil.close(writer); + } + } + }; + } + return mTabPickerDataManager; + } + + @Override + protected void initWidget(View root) { + super.initWidget(root); + + mViewTabPicker.setTabPickerManager(initTabPickerManager()); + mViewTabPicker.setOnTabPickingListener(new TabPickerView.OnTabPickingListener() { + + private boolean isChangeIndex = false; + + @Override + @SuppressWarnings("all") + public void onSelected(final int position) { + final int index = mViewPager.getCurrentItem(); + mViewPager.setCurrentItem(position); + if (position == index) { + mAdapter.commitUpdate(); + // notifyDataSetChanged为什么会导致TabLayout位置偏移,而且需要延迟设置才能起效??? + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + mLayoutTab.getTabAt(position).select(); + } + }, 50); + } + } + + @Override + public void onRemove(int position, SubTab tab) { + isChangeIndex = true; + } + + @Override + public void onInsert(SubTab tab) { + isChangeIndex = true; + } + + @Override + public void onMove(int op, int np) { + isChangeIndex = true; + } + + @Override + public void onRestore(final List mActiveDataSet) { + if (!isChangeIndex) return; + AppOperator.getExecutor().execute(new Runnable() { + @Override + public void run() { + OutputStreamWriter writer = null; + try { + writer = new OutputStreamWriter( + AppContext.getInstance().openFileOutput( + "sub_tab_active.json", Context.MODE_PRIVATE) + , "UTF-8"); + AppOperator.getGson().toJson(mActiveDataSet, writer); + } catch (Exception e) { + e.printStackTrace(); + } finally { + StreamUtil.close(writer); + } + + /*String json = AppOperator.getGson().toJson(mActiveDataSet); + FileOutputStream fos = null; + try { + fos = AppContext.getInstance().openFileOutput("sub_tab_active.json", + Context.MODE_PRIVATE); + fos.write(json.getBytes("UTF-8")); + fos.flush(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + StreamUtil.close(fos); + }*/ + } + }); + isChangeIndex = false; + tabs.clear(); + tabs.addAll(mActiveDataSet); + mAdapter.notifyDataSetChanged(); + } + }); + + mViewTabPicker.setOnShowAnimation(new TabPickerView.Action1() { + @Override + public void call(ViewPropertyAnimator animator) { + mViewArrowDown.setEnabled(false); + activity.toggleNavTabView(false); + mViewArrowDown.animate() + .rotation(225) + .setDuration(380) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animator) { + super.onAnimationEnd(animator); + mViewArrowDown.setRotation(45); + mViewArrowDown.setEnabled(true); + } + }).start(); + + } + }); + + mViewTabPicker.setOnHideAnimator(new TabPickerView.Action1() { + @Override + public void call(ViewPropertyAnimator animator) { + mViewArrowDown.setEnabled(false); + activity.toggleNavTabView(true); + mViewArrowDown.animate() + .rotation(-180) + .setDuration(380) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animator) { + super.onAnimationEnd(animator); + mViewArrowDown.setRotation(0); + mViewArrowDown.setEnabled(true); + } + }); + } + }); + + tabs = new ArrayList<>(); + tabs.addAll(mViewTabPicker.getTabPickerManager().getActiveDataSet()); + for (SubTab tab : tabs) { + mLayoutTab.addTab(mLayoutTab.newTab().setText(tab.getName())); + } + + mViewPager.setAdapter(mAdapter = new FragmentPagerAdapter(getChildFragmentManager()) { + @Override + public Fragment getItem(int position) { + return SubFragment.newInstance(getContext(), tabs.get(position)); + } + + @Override + public int getCount() { + return tabs.size(); + } + + @Override + public CharSequence getPageTitle(int position) { + return tabs.get(position).getName(); + } + + @Override + public void setPrimaryItem(ViewGroup container, int position, Object object) { + super.setPrimaryItem(container, position, object); + if (mCurFragment == null) { + commitUpdate(); + } + mCurFragment = (Fragment) object; + } + + //this is called when notifyDataSetChanged() is called + @Override + public int getItemPosition(Object object) { + return PagerAdapter.POSITION_NONE; + } + + }); + mViewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { + @Override + public void onPageScrollStateChanged(int state) { + super.onPageScrollStateChanged(state); + if (state == ViewPager.SCROLL_STATE_IDLE) { + mAdapter.commitUpdate(); + } + } + }); + mLayoutTab.setupWithViewPager(mViewPager); + mLayoutTab.setSmoothScrollingEnabled(true); + } + + @Override + protected int getContentLayoutId() { + return R.layout.fragment_dynamic_tab; + } + + @Override + protected int getTitleRes() { + return R.string.main_tab_name_news; + } + + @OnClick(R.id.iv_arrow_down) + void onClickArrow() { + if (mViewArrowDown.getRotation() != 0) { + mViewTabPicker.onTurnBack(); + } else { + mViewTabPicker.show(mLayoutTab.getSelectedTabPosition()); + } + } + + @Override + protected int getIconRes() { + return R.mipmap.btn_search_normal; + } + + @Override + protected View.OnClickListener getIconClickListener() { + return new View.OnClickListener() { + @Override + public void onClick(View v) { + SearchActivity.show(getContext()); + } + }; + } + + + @Override + public void onTabReselect() { + if (mCurFragment != null && mCurFragment instanceof OnTabReselectListener) { + ((OnTabReselectListener) mCurFragment).onTabReselect(); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/main/tabs/ExploreFragment.java b/app/src/main/java/net/oschina/app/improve/main/tabs/ExploreFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..971ceb8ec48f3fb95c580bd36897de9350740f82 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/main/tabs/ExploreFragment.java @@ -0,0 +1,99 @@ +package net.oschina.app.improve.main.tabs; + +import android.os.Bundle; +import android.view.View; + +import net.oschina.app.R; +import net.oschina.app.bean.SimpleBackPage; +import net.oschina.app.improve.base.fragments.BaseTitleFragment; +import net.oschina.app.improve.bean.SubTab; +import net.oschina.app.improve.main.discover.ShakePresentActivity; +import net.oschina.app.improve.search.activities.SearchActivity; +import net.oschina.app.util.UIHelper; + +import butterknife.Bind; +import butterknife.OnClick; + +/** + * Created by fei on 2016/9/6. + * desc: + */ + +public class ExploreFragment extends BaseTitleFragment implements View.OnClickListener { + + @Bind(R.id.rl_soft) + View mRlActive; + + @Bind(R.id.rl_scan) + View mScan; + + @Override + protected int getIconRes() { + return R.mipmap.btn_search_normal; + } + + @Override + protected View.OnClickListener getIconClickListener() { + return new View.OnClickListener() { + @Override + public void onClick(View v) { + SearchActivity.show(getContext()); + } + }; + } + + @Override + protected int getContentLayoutId() { + return R.layout.fragment_explore; + } + + @Override + protected int getTitleRes() { + return R.string.main_tab_name_explore; + } + + @OnClick({R.id.rl_soft, R.id.rl_scan, R.id.rl_shake, R.id.layout_events}) + @Override + public void onClick(View v) { + int id = v.getId(); + switch (id) { + case R.id.rl_soft: + UIHelper.showSimpleBack(getActivity(), + SimpleBackPage.OPEN_SOURCE_SOFTWARE); + break; + case R.id.rl_scan: + UIHelper.showScanActivity(getActivity()); + break; + case R.id.rl_shake: + showShake(); + break; + case R.id.layout_events: + SubTab tab = new SubTab(); + + SubTab.Banner banner = tab.new Banner(); + banner.setCatalog(3); + banner.setHref("https://www.oschina.net/action/apiv2//banner?catalog=3"); + tab.setBanner(banner); + + tab.setName("线下活动"); + tab.setFixed(false); + tab.setHref("https://www.oschina.net/action/apiv2/sub_list?token=727d77c15b2ca641fff392b779658512"); + tab.setNeedLogin(false); + tab.setSubtype(1); + tab.setOrder(74); + tab.setToken("727d77c15b2ca641fff392b779658512"); + tab.setType(5); + + Bundle bundle = new Bundle(); + bundle.putSerializable("sub_tab", tab); + + UIHelper.showSimpleBack(getContext(), SimpleBackPage.OUTLINE_EVENTS, bundle); + default: + break; + } + } + + private void showShake() { + ShakePresentActivity.show(getActivity()); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/main/tabs/TweetViewPagerFragment.java b/app/src/main/java/net/oschina/app/improve/main/tabs/TweetViewPagerFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..e73645ff852c56bb4705ad41e15100e213861e2b --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/main/tabs/TweetViewPagerFragment.java @@ -0,0 +1,109 @@ +package net.oschina.app.improve.main.tabs; + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.View; + +import net.oschina.app.R; +import net.oschina.app.improve.base.fragments.BaseGeneralListFragment; +import net.oschina.app.improve.base.fragments.BaseGeneralRecyclerFragment; +import net.oschina.app.improve.base.fragments.BaseViewPagerFragment; +import net.oschina.app.improve.bean.SubTab; +import net.oschina.app.improve.main.subscription.SubFragment; +import net.oschina.app.improve.search.activities.SearchActivity; +import net.oschina.app.improve.tweet.fragments.TweetFragment; +import net.oschina.app.interf.OnTabReselectListener; + +/** + * Created by fei + * on 2016/9/5. + *

    + * Changed qiujuer + * on 2016/9/5. + */ +public class TweetViewPagerFragment extends BaseViewPagerFragment implements OnTabReselectListener { + + /** + * @param catalog {@link TweetFragment} + * @return Bundle + */ + private Bundle getBundle(int catalog) { + Bundle bundle = new Bundle(); + bundle.putInt(TweetFragment.BUNDLE_KEY_REQUEST_CATALOG, catalog); + return bundle; + } + + @Override + public void onTabReselect() { + + if (mBaseViewPager != null) { + BaseViewPagerAdapter pagerAdapter = (BaseViewPagerAdapter) mBaseViewPager.getAdapter(); + Fragment fragment = pagerAdapter.getCurFragment(); + if (fragment != null) { + if (fragment instanceof BaseGeneralListFragment) + ((BaseGeneralListFragment) fragment).onTabReselect(); + else if (fragment instanceof BaseGeneralRecyclerFragment) + ((BaseGeneralRecyclerFragment) fragment).onTabReselect(); + } + } + } + + @Override + protected PagerInfo[] getPagers() { + SubTab tab = new SubTab(); + tab.setType(3); + tab.setFixed(false); + tab.setName("每日乱弹"); + tab.setNeedLogin(false); + tab.setHref("https://www.oschina.net/action/apiv2/sub_list?token=263ee86f538884e70ee1ee50aed759b6"); + tab.setSubtype(5); + tab.setToken("263ee86f538884e70ee1ee50aed759b6"); + + Bundle bundle = new Bundle(); + bundle.putSerializable("sub_tab", tab); + + /*return new PagerInfo[]{ + new PagerInfo("最新动弹", TweetFragment.class, + getBundle(TweetFragment.CATALOG_NEW)), + new PagerInfo("好友动弹", TweetFragment.class, + getBundle(TweetFragment.CATALOG_FRIENDS)), + new PagerInfo("我的动弹", TweetFragment.class, + getBundle(TweetFragment.CATALOG_MYSELF)), + new PagerInfo("热门动弹", TweetFragment.class, + getBundle(TweetFragment.CATALOG_HOT)), + + };*/ + return new PagerInfo[]{ +// new PagerInfo("推荐话题", TopicTweetFragment.class, null), + new PagerInfo("最新动弹", TweetFragment.class, + getBundle(TweetFragment.CATALOG_NEW)), + new PagerInfo("热门动弹", TweetFragment.class, + getBundle(TweetFragment.CATALOG_HOT)), + new PagerInfo("每日乱弹", SubFragment.class, + bundle), + new PagerInfo("我的动弹", TweetFragment.class, + getBundle(TweetFragment.CATALOG_MYSELF)) + + }; + } + + @Override + protected int getTitleRes() { + return R.string.main_tab_name_tweet; + } + + @Override + protected int getIconRes() { + return R.mipmap.btn_search_normal; + } + + @Override + protected View.OnClickListener getIconClickListener() { + return new View.OnClickListener() { + @Override + public void onClick(View v) { + SearchActivity.show(getContext()); + } + }; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/main/update/CheckUpdateManager.java b/app/src/main/java/net/oschina/app/improve/main/update/CheckUpdateManager.java new file mode 100644 index 0000000000000000000000000000000000000000..27615ae40f638da1d7f7cfc4d67140d4c09133a4 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/main/update/CheckUpdateManager.java @@ -0,0 +1,110 @@ +package net.oschina.app.improve.main.update; + +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.support.v7.app.AlertDialog; + +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.AppContext; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.bean.Version; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.utils.DialogHelper; +import net.oschina.app.util.TDevice; + +import java.util.List; + +import cz.msebera.android.httpclient.Header; + +/** + * Created by haibin + * on 2016/10/19. + */ + +public class CheckUpdateManager { + + + private ProgressDialog mWaitDialog; + private Context mContext; + private boolean mIsShowDialog; + private RequestPermissions mCaller; + + public CheckUpdateManager(Context context, boolean showWaitingDialog) { + this.mContext = context; + mIsShowDialog = showWaitingDialog; + if (mIsShowDialog) { + mWaitDialog = DialogHelper.getProgressDialog(mContext); + mWaitDialog.setMessage("正在检查中..."); + mWaitDialog.setCancelable(false); + mWaitDialog.setCanceledOnTouchOutside(false); + } + } + + + public void checkUpdate() { + if (mIsShowDialog) { + mWaitDialog.show(); + } + OSChinaApi.checkUpdate(new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + if (mIsShowDialog) { + DialogHelper.getMessageDialog(mContext, "网络异常,无法获取新版本信息").show(); + } + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + ResultBean> bean = AppOperator.createGson() + .fromJson(responseString, new TypeToken>>() { + }.getType()); + if (bean != null && bean.isSuccess()) { + List versions = bean.getResult(); + if (versions.size() > 0) { + final Version version = versions.get(0); + int curVersionCode = TDevice.getVersionCode(AppContext + .getInstance().getPackageName()); + if (curVersionCode < Integer.parseInt(version.getCode())) { + AlertDialog.Builder dialog = DialogHelper.getConfirmDialog(mContext, version.getMessage(), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + mCaller.call(version); + } + }); + dialog.setTitle("发现新版本"); + dialog.show(); + } else { + if (mIsShowDialog) { + DialogHelper.getMessageDialog(mContext, "已经是新版本了").show(); + } + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void onFinish() { + super.onFinish(); + if (mIsShowDialog) { + mWaitDialog.dismiss(); + } + } + }); + } + + public void setCaller(RequestPermissions caller) { + this.mCaller = caller; + } + + public interface RequestPermissions { + void call(Version version); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/main/update/DownloadService.java b/app/src/main/java/net/oschina/app/improve/main/update/DownloadService.java new file mode 100644 index 0000000000000000000000000000000000000000..ec7fb8e2509808e17ea948f6f5aea9afa3dbb8b4 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/main/update/DownloadService.java @@ -0,0 +1,206 @@ +package net.oschina.app.improve.main.update; + +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.support.annotation.Nullable; +import android.widget.RemoteViews; + +import net.oschina.app.AppConfig; +import net.oschina.app.R; +import net.oschina.app.improve.main.MainActivity; +import net.oschina.common.utils.StreamUtil; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; + +/** + * 下载服务 + * Created by haibin + * on 2016/10/19. + */ +@SuppressWarnings("all") +public class DownloadService extends Service { + public static boolean isDownload = false; + + private String mUrl; + private String mTitle = "正在下载"; + private String saveFileName = AppConfig.DEFAULT_SAVE_FILE_PATH; + + private NotificationManager mNotificationManager; + private Notification mNotification; + + private Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case 0: + mNotificationManager.cancel(0); + installApk(); + break; + case 1: + int rate = msg.arg1; + if (rate < 100) { + RemoteViews views = mNotification.contentView; + views.setTextViewText(R.id.tv_download_progress, mTitle + "(" + rate + + "%" + ")"); + views.setProgressBar(R.id.pb_progress, 100, rate, + false); + } else { + // 下载完毕后变换通知形式 + mNotification.flags = Notification.FLAG_AUTO_CANCEL; + mNotification.contentView = null; + Intent intent = new Intent(getApplicationContext(), MainActivity.class); + + intent.putExtra("completed", "yes"); + + PendingIntent contentIntent = PendingIntent.getActivity( + getApplicationContext(), 0, intent, + PendingIntent.FLAG_UPDATE_CURRENT); + } + mNotificationManager.notify(0, mNotification); + break; + } + + } + }; + + public static void startService(Context context, String downloadUrl) { + Intent intent = new Intent(context, DownloadService.class); + intent.putExtra("url", downloadUrl); + context.startService(intent); + } + + @Override + public void onCreate() { + super.onCreate(); + isDownload = true; + mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + mUrl = intent.getStringExtra("url"); + File file = new File(saveFileName); + if (!file.exists()) { + file.mkdirs(); + } + final File apkFile = new File(saveFileName + "osc.apk"); + setUpNotification(); + new Thread() { + @Override + public void run() { + try { + downloadUpdateFile(mUrl, apkFile); + } catch (Exception e) { + e.printStackTrace(); + } + } + }.start(); + return super.onStartCommand(intent, flags, startId); + } + + private long downloadUpdateFile(String downloadUrl, File saveFile) throws Exception { + int downloadCount = 0; + int currentSize = 0; + long totalSize = 0; + int updateTotalSize = 0; + + HttpURLConnection httpConnection = null; + InputStream is = null; + FileOutputStream fos = null; + + try { + URL url = new URL(downloadUrl); + httpConnection = (HttpURLConnection) url.openConnection(); + httpConnection.setConnectTimeout(10000); + httpConnection.setReadTimeout(20000); + updateTotalSize = httpConnection.getContentLength(); + if (httpConnection.getResponseCode() == 404) { + throw new Exception("fail!"); + } + is = httpConnection.getInputStream(); + fos = new FileOutputStream(saveFile, false); + byte buffer[] = new byte[2048]; + int readSize = 0; + while ((readSize = is.read(buffer)) > 0) { + + fos.write(buffer, 0, readSize); + totalSize += readSize; + if ((downloadCount == 0) + || (int) (totalSize * 100 / updateTotalSize) - 4 > downloadCount) { + downloadCount += 4; + Message msg = mHandler.obtainMessage(); + msg.what = 1; + msg.arg1 = downloadCount; + mHandler.sendMessage(msg); + } + } + + mHandler.sendEmptyMessage(0); + isDownload = false; + + } finally { + if (httpConnection != null) { + httpConnection.disconnect(); + } + StreamUtil.close(is, fos); + stopSelf(); + } + return totalSize; + } + + private void installApk() { + File file = new File(saveFileName + "osc.apk"); + if (!file.exists()) + return; + Intent intent = new Intent(); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.setAction(Intent.ACTION_VIEW); + intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive"); + startActivity(intent); + } + + private void setUpNotification() { + int icon = R.mipmap.ic_launcher; + CharSequence tickerText = "开始下载"; + long when = System.currentTimeMillis(); + mNotification = new Notification(icon, tickerText, when); + + mNotification.flags = Notification.FLAG_ONGOING_EVENT; + + RemoteViews contentView = new RemoteViews(getPackageName(), + R.layout.layout_notification_view); + contentView.setTextViewText(R.id.tv_download_progress, mTitle); + mNotification.contentView = contentView; + + Intent intent = new Intent(this, MainActivity.class); + PendingIntent contentIntent = PendingIntent.getActivity(this, 0, + intent, PendingIntent.FLAG_UPDATE_CURRENT); + + mNotification.contentIntent = contentIntent; + mNotificationManager.notify(0, mNotification); + } + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public void onDestroy() { + isDownload = false; + super.onDestroy(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/media/ImageFolderPopupWindow.java b/app/src/main/java/net/oschina/app/improve/media/ImageFolderPopupWindow.java new file mode 100644 index 0000000000000000000000000000000000000000..dcb380b5bd781067ee0bbf71ecc4dd3878d9148a --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/media/ImageFolderPopupWindow.java @@ -0,0 +1,89 @@ +package net.oschina.app.improve.media; + +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.PopupWindow; + +import net.oschina.app.R; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.media.adapter.ImageFolderAdapter; +import net.oschina.app.improve.media.bean.ImageFolder; + +/** + * 图片选择器菜单选择界面 + */ +public class ImageFolderPopupWindow extends PopupWindow implements + View.OnAttachStateChangeListener, + BaseRecyclerAdapter.OnItemClickListener { + private ImageFolderAdapter mAdapter; + private RecyclerView mFolderView; + private Callback mCallback; + + public ImageFolderPopupWindow(Context context, Callback callback) { + super(LayoutInflater.from(context).inflate(R.layout.popup_window_folder, null), + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); + + mCallback = callback; + + // init + setAnimationStyle(R.style.popup_anim_style_alpha); + setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + setOutsideTouchable(true); + setFocusable(true); + + // content + View content = getContentView(); + content.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + dismiss(); + } + }); + content.addOnAttachStateChangeListener(this); + + mFolderView = (RecyclerView) content.findViewById(R.id.rv_popup_folder); + mFolderView.setLayoutManager(new LinearLayoutManager(context)); + + } + + public void setAdapter(ImageFolderAdapter adapter) { + this.mAdapter = adapter; + mFolderView.setAdapter(adapter); + mAdapter.setOnItemClickListener(this); + } + + @Override + public void onViewAttachedToWindow(View v) { + final Callback callback = mCallback; + if (callback != null) + callback.onShow(); + } + + @Override + public void onViewDetachedFromWindow(View v) { + final Callback callback = mCallback; + if (callback != null) + callback.onDismiss(); + } + + @Override + public void onItemClick(int position, long itemId) { + final Callback callback = mCallback; + if (callback != null) + callback.onSelect(this, mAdapter.getItem(position)); + } + + public interface Callback { + void onSelect(ImageFolderPopupWindow popupWindow, ImageFolder model); + + void onDismiss(); + + void onShow(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/media/ImageGalleryActivity.java b/app/src/main/java/net/oschina/app/improve/media/ImageGalleryActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..bcda1ff5086619d52b641c89265db84c65ed3ed7 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/media/ImageGalleryActivity.java @@ -0,0 +1,434 @@ +package net.oschina.app.improve.media; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.Intent; +import android.graphics.BitmapFactory; +import android.graphics.Point; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.os.Environment; +import android.support.v4.view.PagerAdapter; +import android.support.v4.view.ViewPager; +import android.view.Display; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.bumptech.glide.DrawableRequestBuilder; +import com.bumptech.glide.load.engine.DiskCacheStrategy; +import com.bumptech.glide.load.resource.drawable.GlideDrawable; +import com.bumptech.glide.request.RequestListener; +import com.bumptech.glide.request.target.Target; + +import net.oschina.app.R; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.base.activities.BaseActivity; +import net.oschina.common.utils.BitmapUtil; +import net.oschina.common.utils.StreamUtil; +import net.qiujuer.genius.ui.widget.Loading; + +import java.io.File; +import java.util.concurrent.Future; + + +/** + * 图片预览Activity + */ +public class ImageGalleryActivity extends BaseActivity implements ViewPager.OnPageChangeListener, View.OnClickListener { + public static final String KEY_IMAGE = "images"; + public static final String KEY_COOKIE = "cookie_need"; + public static final String KEY_POSITION = "position"; + public static final String KEY_NEED_SAVE = "save"; + private PreviewerViewPager mImagePager; + private TextView mIndexText; + private String[] mImageSources; + private int mCurPosition; + private boolean mNeedSaveLocal; + private boolean mNeedCookie; + + public static void show(Context context, String images) { + show(context, images, true); + } + + public static void show(Context context, String images, boolean needSaveLocal) { + if (images == null) + return; + show(context, new String[]{images}, 0, needSaveLocal); + } + + public static void show(Context context, String images, boolean needSaveLocal, boolean needCookie) { + if (images == null) + return; + show(context, new String[]{images}, 0, needSaveLocal, needCookie); + } + + public static void show(Context context, String[] images, int position) { + show(context, images, position, true); + } + + public static void show(Context context, String[] images, int position, boolean needSaveLocal) { + show(context, images, position, needSaveLocal, false); + } + + public static void show(Context context, String[] images, int position, boolean needSaveLocal, boolean needCookie) { + if (images == null || images.length == 0) + return; + Intent intent = new Intent(context, ImageGalleryActivity.class); + intent.putExtra(KEY_IMAGE, images); + intent.putExtra(KEY_POSITION, position); + intent.putExtra(KEY_NEED_SAVE, needSaveLocal); + intent.putExtra(KEY_COOKIE, needCookie); + context.startActivity(intent); + } + + @Override + protected boolean initBundle(Bundle bundle) { + mImageSources = bundle.getStringArray(KEY_IMAGE); + mCurPosition = bundle.getInt(KEY_POSITION, 0); + mNeedSaveLocal = bundle.getBoolean(KEY_NEED_SAVE, true); + mNeedCookie = bundle.getBoolean(KEY_COOKIE, false); + return mImageSources != null; + } + + @Override + protected void initWindow() { + super.initWindow(); + getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT); + } + + @Override + protected int getContentView() { + return R.layout.activity_image_gallery; + } + + @Override + protected void initWidget() { + super.initWidget(); + setTitle(""); + mImagePager = (PreviewerViewPager) findViewById(R.id.vp_image); + mIndexText = (TextView) findViewById(R.id.tv_index); + mImagePager.addOnPageChangeListener(this); + if (mNeedSaveLocal) + findViewById(R.id.iv_save).setOnClickListener(this); + else + findViewById(R.id.iv_save).setVisibility(View.GONE); + } + + @Override + protected void initData() { + super.initData(); + int len = mImageSources.length; + if (mCurPosition < 0 || mCurPosition >= len) + mCurPosition = 0; + + // If only one, we not need the text to show + if (len == 1) + mIndexText.setVisibility(View.GONE); + + mImagePager.setAdapter(new ViewPagerAdapter()); + mImagePager.setCurrentItem(mCurPosition); + // First we call to init the TextView + onPageSelected(mCurPosition); + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.iv_save: + saveToFile(); + break; + } + } + + private void saveToFile() { + if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + Toast.makeText(this, R.string.gallery_save_file_not_have_external_storage, Toast.LENGTH_SHORT).show(); + return; + } + + String path = mImageSources[mCurPosition]; + + Object urlOrPath; + // Do load + if (mNeedCookie) + urlOrPath = AppOperator.getGlideUrlByUser(path); + else + urlOrPath = path; + + // In this save max image size is source + final Future future = getImageLoader() + .load(urlOrPath) + .downloadOnly(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL); + + AppOperator.runOnThread(new Runnable() { + @Override + public void run() { + try { + File sourceFile = future.get(); + if (sourceFile == null || !sourceFile.exists()) + return; + String extension = BitmapUtil.getExtension(sourceFile.getAbsolutePath()); + String extDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + .getAbsolutePath() + File.separator + "开源中国"; + File extDirFile = new File(extDir); + if (!extDirFile.exists()) { + if (!extDirFile.mkdirs()) { + // If mk dir error + callSaveStatus(false, null); + return; + } + } + final File saveFile = new File(extDirFile, String.format("IMG_%s.%s", System.currentTimeMillis(), extension)); + final boolean isSuccess = StreamUtil.copyFile(sourceFile, saveFile); + runOnUiThread(new Runnable() { + @Override + public void run() { + callSaveStatus(isSuccess, saveFile); + } + }); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + + private void callSaveStatus(boolean success, File savePath) { + if (success) { + // notify + Uri uri = Uri.fromFile(savePath); + sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri)); + Toast.makeText(ImageGalleryActivity.this, R.string.gallery_save_file_success, Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(ImageGalleryActivity.this, R.string.gallery_save_file_failed, Toast.LENGTH_SHORT).show(); + } + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + + } + + @Override + public void onPageSelected(int position) { + mCurPosition = position; + mIndexText.setText(String.format("%s/%s", (position + 1), mImageSources.length)); + } + + @Override + public void onPageScrollStateChanged(int state) { + + } + + private Point mDisplayDimens; + + @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2) + @SuppressWarnings("deprecation") + private synchronized Point getDisplayDimens() { + if (mDisplayDimens != null) { + return mDisplayDimens; + } + Point displayDimens; + WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); + Display display = windowManager.getDefaultDisplay(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) { + displayDimens = new Point(); + display.getSize(displayDimens); + } else { + displayDimens = new Point(display.getWidth(), display.getHeight()); + } + + // In this we can only get 85% width and 60% height + //displayDimens.y = (int) (displayDimens.y * 0.60f); + //displayDimens.x = (int) (displayDimens.x * 0.85f); + + mDisplayDimens = displayDimens; + return mDisplayDimens; + } + + private class ViewPagerAdapter extends PagerAdapter implements ImagePreviewView.OnReachBorderListener { + + private View.OnClickListener mFinishClickListener; + + @Override + public int getCount() { + return mImageSources.length; + } + + @Override + public boolean isViewFromObject(View view, Object object) { + return view == object; + } + + @Override + public Object instantiateItem(ViewGroup container, int position) { + View view = LayoutInflater.from(container.getContext()) + .inflate(R.layout.lay_gallery_page_item_contener, container, false); + ImagePreviewView previewView = (ImagePreviewView) view.findViewById(R.id.iv_preview); + previewView.setOnReachBorderListener(this); + Loading loading = (Loading) view.findViewById(R.id.loading); + ImageView defaultView = (ImageView) view.findViewById(R.id.iv_default); + + // Do load + if (mNeedCookie) + loadImage(AppOperator.getGlideUrlByUser(mImageSources[position]), + previewView, defaultView, loading); + else + loadImage(mImageSources[position], previewView, defaultView, loading); + + previewView.setOnClickListener(getListener()); + container.addView(view); + return view; + } + + private View.OnClickListener getListener() { + if (mFinishClickListener == null) { + mFinishClickListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }; + } + return mFinishClickListener; + } + + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + container.removeView((View) object); + } + + @Override + public void onReachBorder(boolean isReached) { + mImagePager.isInterceptable(isReached); + } + + private void loadImage(final T urlOrPath, + final ImageView previewView, + final ImageView defaultView, + final Loading loading) { + + loadImageDoDownAndGetOverrideSize(urlOrPath, new DoOverrideSizeCallback() { + @Override + public void onDone(int overrideW, int overrideH, boolean isTrue) { + DrawableRequestBuilder builder = getImageLoader() + .load(urlOrPath) + .listener(new RequestListener() { + @Override + public boolean onException(Exception e, + T model, + Target target, + boolean isFirstResource) { + if (e != null) + e.printStackTrace(); + loading.stop(); + loading.setVisibility(View.GONE); + defaultView.setVisibility(View.VISIBLE); + return false; + } + + @Override + public boolean onResourceReady(GlideDrawable resource, + T model, + Target target, + boolean isFromMemoryCache, + boolean isFirstResource) { + loading.stop(); + loading.setVisibility(View.GONE); + return false; + } + }).diskCacheStrategy(DiskCacheStrategy.SOURCE); + + // If download or get option error we not set override + if (isTrue && overrideW > 0 && overrideH > 0) { + builder = builder.override(overrideW, overrideH); + } + + builder.into(previewView); + } + }); + } + + private void loadImageDoDownAndGetOverrideSize(final T urlOrPath, final DoOverrideSizeCallback callback) { + // In this save max image size is source + final Future future = getImageLoader().load(urlOrPath) + .downloadOnly(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL); + + AppOperator.runOnThread(new Runnable() { + @Override + public void run() { + try { + File sourceFile = future.get(); + + BitmapFactory.Options options = BitmapUtil.createOptions(); + // First decode with inJustDecodeBounds=true to checkShare dimensions + options.inJustDecodeBounds = true; + // First decode with inJustDecodeBounds=true to checkShare dimensions + BitmapFactory.decodeFile(sourceFile.getAbsolutePath(), options); + + int width = options.outWidth; + int height = options.outHeight; + BitmapUtil.resetOptions(options); + + if (width > 0 && height > 0) { + // Get Screen + final Point point = getDisplayDimens(); + + // This max size + final int maxLen = Math.min(Math.min(point.y, point.x) * 5, 1366 * 3); + + // Init override size + final int overrideW, overrideH; + + if ((width / (float) height) > (point.x / (float) point.y)) { + overrideH = Math.min(height, point.y); + overrideW = Math.min(width, maxLen); + } else { + overrideW = Math.min(width, point.x); + overrideH = Math.min(height, maxLen); + } + + // Call back on main thread + runOnUiThread(new Runnable() { + @Override + public void run() { + callback.onDone(overrideW, overrideH, true); + } + }); + } else { + // Call back on main thread + runOnUiThread(new Runnable() { + @Override + public void run() { + callback.onDone(0, 0, false); + } + }); + } + } catch (Exception e) { + e.printStackTrace(); + + // Call back on main thread + runOnUiThread(new Runnable() { + @Override + public void run() { + callback.onDone(0, 0, false); + } + }); + } + } + }); + } + + + } + + interface DoOverrideSizeCallback { + void onDone(int overrideW, int overrideH, boolean isTrue); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/media/ImagePreviewView.java b/app/src/main/java/net/oschina/app/improve/media/ImagePreviewView.java new file mode 100644 index 0000000000000000000000000000000000000000..61604a1a68536a5eb3ff50faa86f25a2f58b52b4 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/media/ImagePreviewView.java @@ -0,0 +1,542 @@ +package net.oschina.app.improve.media; + +import android.animation.FloatEvaluator; +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.GestureDetector; +import android.view.MotionEvent; +import android.view.ScaleGestureDetector; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.DecelerateInterpolator; +import android.widget.ImageView; + +/** + * 支持图片预览, 放大,缩小,位置自适应,双击放大缩小 + * Created by thanatosx on 16/5/3. + */ +public class ImagePreviewView extends ImageView { + + private ScaleGestureDetector mScaleDetector; + private GestureDetector mFlatDetector; + + private float scale = 1.f; + private static final float mMaxScale = 4.f; + private static final float mMinScale = 0.4f; + private float translateLeft = 0.f; + private float translateTop = 0.f; + private int mBoundWidth = 0; + private int mBoundHeight = 0; + private boolean isAutoScale = false; + + private ValueAnimator resetScaleAnimator; + private ValueAnimator resetXAnimator; + private ValueAnimator resetYAnimator; + private ValueAnimator.AnimatorUpdateListener onScaleAnimationUpdate; + private ValueAnimator.AnimatorUpdateListener onTranslateXAnimationUpdate; + private ValueAnimator.AnimatorUpdateListener onTranslateYAnimationUpdate; + + private FloatEvaluator mFloatEvaluator = new FloatEvaluator(); + private AccelerateInterpolator mAccInterpolator = new AccelerateInterpolator(); + private DecelerateInterpolator mDecInterpolator = new DecelerateInterpolator(); + + private OnReachBorderListener onReachBorderListener; + + public interface OnReachBorderListener { + void onReachBorder(boolean isReached); + } + + public void setOnReachBorderListener(OnReachBorderListener l) { + onReachBorderListener = l; + } + + public ImagePreviewView(Context context) { + this(context, null); + } + + public ImagePreviewView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ImagePreviewView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + mScaleDetector = new ScaleGestureDetector(getContext(), new ScaleListener()); + mFlatDetector = new GestureDetector(getContext(), new FlatGestureListener()); + } + + /** + * 重置伸缩动画的监听器 + * + * @return + */ + public ValueAnimator.AnimatorUpdateListener getOnScaleAnimationUpdate() { + if (onScaleAnimationUpdate != null) return onScaleAnimationUpdate; + onScaleAnimationUpdate = new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + scale = (float) animation.getAnimatedValue(); + invalidate(); + } + }; + return onScaleAnimationUpdate; + } + + /** + * 重置水平动画的监听器 + * + * @return + */ + public ValueAnimator.AnimatorUpdateListener getOnTranslateXAnimationUpdate() { + if (onTranslateXAnimationUpdate != null) return onTranslateXAnimationUpdate; + onTranslateXAnimationUpdate = new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + translateLeft = (float) animation.getAnimatedValue(); + invalidate(); + } + }; + return onTranslateXAnimationUpdate; + } + + /** + * 重置垂直动画的监听器 + * + * @return + */ + public ValueAnimator.AnimatorUpdateListener getOnTranslateYAnimationUpdate() { + if (onTranslateYAnimationUpdate != null) return onTranslateYAnimationUpdate; + onTranslateYAnimationUpdate = new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + translateTop = (float) animation.getAnimatedValue(); + invalidate(); + } + }; + return onTranslateYAnimationUpdate; + } + + /** + * 重置伸缩 + * + * @return the animator control scale value + */ + private ValueAnimator getResetScaleAnimator() { + if (resetScaleAnimator != null) { + resetScaleAnimator.removeAllUpdateListeners(); + } else { + resetScaleAnimator = ValueAnimator.ofFloat(); + } + resetScaleAnimator.setDuration(150); + resetScaleAnimator.setInterpolator(mAccInterpolator); + resetScaleAnimator.setEvaluator(mFloatEvaluator); + return resetScaleAnimator; + } + + /** + * 水平方向的重置动画 + * + * @return + */ + private ValueAnimator getResetXAnimator() { + if (resetXAnimator != null) { + resetXAnimator.removeAllUpdateListeners(); + } else { + resetXAnimator = ValueAnimator.ofFloat(); + } + resetXAnimator.setDuration(150); + resetXAnimator.setInterpolator(mAccInterpolator); + resetXAnimator.setEvaluator(mFloatEvaluator); + return resetXAnimator; + } + + /** + * 垂直方向的重置动画 + * + * @return + */ + private ValueAnimator getResetYAnimator() { + if (resetYAnimator != null) { + resetYAnimator.removeAllUpdateListeners(); + } else { + resetYAnimator = ValueAnimator.ofFloat(); + } + resetYAnimator.setDuration(150); + resetYAnimator.setInterpolator(mAccInterpolator); + resetYAnimator.setEvaluator(mFloatEvaluator); + return resetYAnimator; + } + + private void cancelAnimation() { + if (resetScaleAnimator != null && resetScaleAnimator.isRunning()) { + resetScaleAnimator.cancel(); + } + if (resetXAnimator != null && resetXAnimator.isRunning()) { + resetXAnimator.cancel(); + } + if (resetYAnimator != null && resetYAnimator.isRunning()) { + resetYAnimator.cancel(); + } + } + + /** + * @return 如果是正数, 左边有空隙, 如果是负数, 右边有空隙, 如果是0, 代表两边都没有空隙 + */ + private float getDiffX() { + final float mScaledWidth = mBoundWidth * scale; + return translateLeft >= 0 + ? translateLeft + : getWidth() - translateLeft - mScaledWidth > 0 + ? -(getWidth() - translateLeft - mScaledWidth) + : 0; + } + + /** + * @return 如果是正数, 上面有空隙, 如果是负数, 下面有空隙, 如果是0, 代表两边都没有空隙 + */ + private float getDiffY() { + final float mScaledHeight = mBoundHeight * scale; + return translateTop >= 0 + ? translateTop + : getHeight() - translateTop - mScaledHeight > 0 + ? -(getHeight() - translateTop - mScaledHeight) + : 0; + } + + + @Override + public boolean onTouchEvent(MotionEvent event) { + final int action = event.getAction(); + + // 清理动画 + if (action == MotionEvent.ACTION_DOWN) { + cancelAnimation(); + } + + mFlatDetector.onTouchEvent(event); + mScaleDetector.onTouchEvent(event); + + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { + if (isAutoScale) { + isAutoScale = false; + } else { + if (scale < 1) { + ValueAnimator animator = getResetScaleAnimator(); + animator.setFloatValues(scale, 1.f); + animator.addUpdateListener(getOnScaleAnimationUpdate()); + animator.start(); + } + final float mScaledWidth = mBoundWidth * scale; + final float mScaledHeight = mBoundHeight * scale; + + final float mDiffX = getDiffX(); + final float mDiffY = getDiffY(); + + // 左右边界重置 + if (mScaledWidth >= getWidth() && mDiffX != 0) { + ValueAnimator animator = getResetXAnimator(); + animator.setFloatValues(translateLeft, translateLeft - mDiffX); + animator.addUpdateListener(getOnTranslateXAnimationUpdate()); + animator.start(); + } + + // 上下边界重置 + if (mScaledHeight >= getHeight() && mDiffY != 0) { + ValueAnimator animator = getResetYAnimator(); + animator.setFloatValues(translateTop, translateTop - mDiffY); + animator.addUpdateListener(getOnTranslateYAnimationUpdate()); + animator.start(); + } + + // width重置到中间位置 + if (mScaledWidth < getWidth() && mScaledHeight >= getHeight() && mDiffX != 0) { + ValueAnimator animator = getResetXAnimator(); + animator.setFloatValues(translateLeft, 0); // 宽度总是填充的 + animator.addUpdateListener(getOnTranslateXAnimationUpdate()); + animator.start(); + } + + // height重置到中间位置 + if (mScaledHeight < getHeight() && mScaledWidth >= getWidth() && mDiffY != 0) { + ValueAnimator animator = getResetYAnimator(); + animator.setFloatValues(translateTop, (getHeight() - mScaledHeight) / 2.f); + animator.addUpdateListener(getOnTranslateYAnimationUpdate()); + animator.start(); + } + + if (mScaledWidth < getWidth() && mScaledHeight < getHeight()) { + resetDefaultState(); + } + } + } + + return true; + } + + private void resetDefaultState() { + if (translateLeft != 0) { + ValueAnimator mTranslateXAnimator = getResetXAnimator(); + mTranslateXAnimator.setFloatValues(translateLeft, 0); + mTranslateXAnimator.addUpdateListener(getOnTranslateXAnimationUpdate()); + mTranslateXAnimator.start(); + } + + ValueAnimator mTranslateYAnimator = getResetYAnimator(); + mTranslateYAnimator.setFloatValues(translateTop, getDefaultTranslateTop(getHeight(), mBoundHeight)); + mTranslateYAnimator.addUpdateListener(getOnTranslateYAnimationUpdate()); + mTranslateYAnimator.start(); + + } + + @Override + protected boolean setFrame(int l, int t, int r, int b) { + super.setFrame(l, t, r, b); + + Drawable drawable = getDrawable(); + if (drawable == null) return false; + if (mBoundWidth != 0 && mBoundHeight != 0 && scale != 1) return false; + + adjustBounds(getWidth(), getHeight()); + + return true; + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + adjustBounds(w, h); + } + + private void adjustBounds(int width, int height) { + Drawable drawable = getDrawable(); + if (drawable == null) return; + mBoundWidth = drawable.getBounds().width(); + mBoundHeight = drawable.getBounds().height(); + + float scale = (float) mBoundWidth / width; + + mBoundHeight /= scale; + mBoundWidth = width; + + drawable.setBounds(0, 0, mBoundWidth, mBoundHeight); + + translateLeft = 0; + translateTop = getDefaultTranslateTop(height, mBoundHeight); + } + + private float getDefaultTranslateTop(int height, int bh) { + float top = (height - bh) / 2.f; + return top > 0 ? top : 0; + } + + @Override + protected void onDraw(Canvas canvas) { + Drawable mDrawable = getDrawable(); + if (mDrawable == null) return; + + final int mDrawableWidth = mDrawable.getIntrinsicWidth(); + final int mDrawableHeight = mDrawable.getIntrinsicHeight(); + + if (mDrawableWidth == 0 || mDrawableHeight == 0) { + return; // nothing to draw (empty bounds) + } + + int saveCount = canvas.getSaveCount(); + canvas.save(); + + canvas.translate(translateLeft, translateTop); + canvas.scale(scale, scale); + + // 如果先scale,再translate,那么,真实translate的值是要与scale值相乘的 + mDrawable.draw(canvas); + canvas.restoreToCount(saveCount); + } + + private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { + /** + * factor = detector.getCurrentSpan() / detector.getPreviousSpan() + * + * @param detector + * @return + */ + @Override + public boolean onScale(ScaleGestureDetector detector) { + final float mOldScaledWidth = mBoundWidth * scale; + final float mOldScaledHeight = mBoundHeight * scale; + + if (mOldScaledWidth > getWidth() && getDiffX() != 0 || + (mOldScaledHeight > getHeight() && getDiffY() != 0)) return false; + + float factor = detector.getScaleFactor(); + float value = scale; + value += (factor - 1) * 2; + if (value == scale) return true; + if (value <= mMinScale) return false; + if (value > mMaxScale) return false; + scale = value; + final float mScaledWidth = mBoundWidth * scale; + final float mScaledHeight = mBoundHeight * scale; + + // 走了些弯路, 不应该带入translateX计算, 因为二次放大之后计算就不正确了,它应该受scale的制约 + translateLeft = getWidth() / 2.f - (getWidth() / 2.f - translateLeft) * mScaledWidth / mOldScaledWidth; + translateTop = getHeight() / 2.f - (getHeight() / 2.f - translateTop) * mScaledHeight / mOldScaledHeight; + + final float diffX = getDiffX(); + final float diffY = getDiffY(); + + // 考虑宽图, 如果缩小的时候图片左边界到了屏幕左边界,停留在左边界缩小 + if (diffX > 0 && mScaledWidth > getWidth()) { + translateLeft = 0; + } + // 右边界问题 + if (diffX < 0 && mScaledWidth > getWidth()) { + translateLeft = getWidth() - mScaledWidth; + } + + // 考虑到长图,上边界问题 + if (diffY > 0 && mScaledHeight > getHeight()) { + translateTop = 0; + } + + // 下边界问题 + if (diffY < 0 && mScaledHeight > getHeight()) { + translateTop = getHeight() - mScaledHeight; + } + + invalidate(); + return true; + } + + } + + private float getExplicitTranslateLeft(float l) { + final float mScaledWidth = mBoundWidth * scale; + if (l > 0) { + l = 0; + } + if (-l + getWidth() > mScaledWidth) { + l = getWidth() - mScaledWidth; + } + return l; + } + + private float getExplicitTranslateTop(float t) { + final float mScaledHeight = mBoundHeight * scale; + if (t > 0) { + t = 0; + } + if (-t + getHeight() > mScaledHeight) { + t = getHeight() - mScaledHeight; + } + return t; + } + + private class FlatGestureListener extends GestureDetector.SimpleOnGestureListener { + /** + * @param e1 horizontal event + * @param e2 vertical event + * @param distanceX previous X - current X, toward left , is position + * @param distanceY previous Y - current Y, toward up, is position + * @return + */ + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { + final float mScaledWidth = mBoundWidth * scale; + final float mScaledHeight = mBoundHeight * scale; + + if (mScaledHeight > getHeight()) { + translateTop -= distanceY * 1.5; + translateTop = getExplicitTranslateTop(translateTop); + /*if (getDiffY() != 0) { + final float disY = (float) (Math.acos(Math.abs(getDiffY()) / getHeight() * 6) * distanceY); + if (disY == disY) translateTop -= disY; // float 低值溢出变Nan数值 + } else { + translateTop -= distanceY * 1.5; + }*/ + } + + boolean isReachBorder = false; + if (mScaledWidth > getWidth()) { + translateLeft -= distanceX * 1.5; + final float t = getExplicitTranslateLeft(translateLeft); + if (t != translateLeft) isReachBorder = true; + translateLeft = t; + /*if (getDiffX() != 0) { + final float disX = (float) (Math.acos(Math.abs(getDiffX()) / getWidth() * 4) * distanceX); + if (disX == disX) translateLeft -= disX; + } else { + translateLeft -= distanceX * 1.5; + }*/ + } else { + isReachBorder = true; + } + + if (onReachBorderListener != null) + onReachBorderListener.onReachBorder(isReachBorder); + + invalidate(); + return true; + } + + @Override + public boolean onSingleTapConfirmed(MotionEvent e) { + return performClick(); + } + + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + if (mBoundWidth * scale > getWidth()) { + float sx = translateLeft + (1f / 2f) * velocityX * 0.5f * 0.5f; + sx = getExplicitTranslateLeft(sx); + ValueAnimator mResetXAnimator = getResetXAnimator(); + mResetXAnimator.setDuration(300); + mResetXAnimator.setInterpolator(mDecInterpolator); + mResetXAnimator.setFloatValues(translateLeft, sx); + mResetXAnimator.addUpdateListener(getOnTranslateXAnimationUpdate()); + mResetXAnimator.start(); + } + + if (mBoundHeight * scale > getHeight()) { + float sy = translateTop + (1f / 2f) * velocityY * 0.5f * 0.5f; + sy = getExplicitTranslateTop(sy); + ValueAnimator mResetYAnimator = getResetYAnimator(); + mResetYAnimator.setDuration(300); + mResetYAnimator.setInterpolator(mDecInterpolator); + mResetYAnimator.setFloatValues(translateTop, sy); + mResetYAnimator.addUpdateListener(getOnTranslateYAnimationUpdate()); + mResetYAnimator.start(); + } + + return true; + } + + @Override + public boolean onDoubleTap(MotionEvent e) { + isAutoScale = true; + ValueAnimator mResetScaleAnimator = getResetScaleAnimator(); + + if (scale == 1.f) { + mResetScaleAnimator.setFloatValues(1.f, 2.f); + + ValueAnimator mResetXAnimator = getResetXAnimator(); + ValueAnimator mResetYAnimator = getResetYAnimator(); + mResetXAnimator.setFloatValues(translateLeft, (getWidth() - mBoundWidth * 2.f) / 2.f); + mResetYAnimator.setFloatValues(translateTop, getDefaultTranslateTop(getHeight(), mBoundHeight * 2)); + mResetXAnimator.addUpdateListener(getOnTranslateXAnimationUpdate()); + mResetYAnimator.addUpdateListener(getOnTranslateYAnimationUpdate()); + mResetXAnimator.start(); + mResetYAnimator.start(); + } else { + mResetScaleAnimator.setFloatValues(scale, 1.f); + resetDefaultState(); + } + + mResetScaleAnimator.addUpdateListener(getOnScaleAnimationUpdate()); + mResetScaleAnimator.start(); + return true; + } + } + + +} diff --git a/app/src/main/java/net/oschina/app/improve/media/MediaStoreDataFactory.java b/app/src/main/java/net/oschina/app/improve/media/MediaStoreDataFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..8e8bf504770da742c07cb6cf3b27da57f02472d4 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/media/MediaStoreDataFactory.java @@ -0,0 +1,246 @@ +package net.oschina.app.improve.media; + +import android.content.Context; +import android.database.Cursor; +import android.os.Bundle; +import android.provider.MediaStore; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.support.v4.util.ArrayMap; + +import net.oschina.app.improve.media.bean.Image; +import net.oschina.app.improve.media.bean.ImageFolder; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * Created by JuQiu + * on 16/7/28. + */ +public class MediaStoreDataFactory implements LoaderManager.LoaderCallbacks { + private static final String[] IMAGE_PROJECTION = { + MediaStore.Images.Media.DATA, + MediaStore.Images.Media.DISPLAY_NAME, + MediaStore.Images.Media.DATE_ADDED, + MediaStore.Images.Media._ID, + MediaStore.Images.Media.MINI_THUMB_MAGIC, + MediaStore.Images.Media.BUCKET_DISPLAY_NAME}; + + private final List mSource = new ArrayList<>(); + private final Map mFolderSource = new ArrayMap<>(); + private String mRegisterKey = ""; + private PictureSourceCallback mImageCallback; + private FolderSourceCallback mFolderCallback; + private Context mContext; + + public MediaStoreDataFactory(Context context, PictureSourceCallback pictureSourceCallback, + FolderSourceCallback folderSourceCallback) { + this.mContext = context; + this.mImageCallback = pictureSourceCallback; + this.mFolderCallback = folderSourceCallback; + } + + @Override + public Loader onCreateLoader(int id, Bundle args) { + return new CursorLoader(mContext, + MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_PROJECTION, + null, null, IMAGE_PROJECTION[2] + " DESC"); + } + + @Override + public void onLoadFinished(Loader loader, Cursor data) { + if (data != null) { + ArrayList images = new ArrayList<>(); + int count = data.getCount(); + if (count > 0) { + data.moveToFirst(); + do { + String path = data.getString(data.getColumnIndexOrThrow(IMAGE_PROJECTION[0])); + String name = data.getString(data.getColumnIndexOrThrow(IMAGE_PROJECTION[1])); + long dateTime = data.getLong(data.getColumnIndexOrThrow(IMAGE_PROJECTION[2])); + int id = data.getInt(data.getColumnIndexOrThrow(IMAGE_PROJECTION[3])); + String thumbPath = data.getString(data.getColumnIndexOrThrow(IMAGE_PROJECTION[4])); + String bucket = data.getString(data.getColumnIndexOrThrow(IMAGE_PROJECTION[5])); + + Image image = new Image(); + image.setPath(path); + image.setName(name); + image.setDate(dateTime); + image.setId(id); + image.setThumbPath(thumbPath); + image.setFolderName(bucket); + images.add(image); + } while (data.moveToNext()); + } + doSource(images); + } + } + + + private void doSource(List changes) { + final List source = mSource; + if (source.size() == 0) { + source.addAll(changes); + callDataAdded(source); + } + if (changes.size() == 0) { + callDataRemoved(source); + source.clear(); + } else { + // checkShare remove + List removes = new ArrayList<>(); + for (Image image : source) { + if (!changes.contains(image)) + removes.add(image); + } + if (removes.size() > 0) { + source.removeAll(removes); + callDataRemoved(removes); + } + + // checkShare add + List adds = new ArrayList<>(); + for (Image image : changes) { + if (!source.contains(image)) + adds.add(image); + } + if (adds.size() > 0) { + source.addAll(adds); + callDataAdded(adds); + } + } + } + + private void callDataAdded(List images) { + List updateFolder = new ArrayList<>(); + List addFolder = new ArrayList<>(); + List addImages = new ArrayList<>(); + + final Map folderSource = mFolderSource; + for (Image image : images) { + File folderFile = new File(image.getPath()).getParentFile(); + String folderPath = folderFile.getAbsolutePath().toLowerCase(); + if (folderSource.containsKey(folderPath)) { + // update + ImageFolder folder = folderSource.get(folderPath); + folder.getImages().add(image); + if (!addFolder.contains(folder) && !updateFolder.contains(folder)) { + updateFolder.add(folder); + } + } else { + // Add new + ImageFolder folder = new ImageFolder(); + folder.setName(folderFile.getName()); + folder.setPath(folderFile.getAbsolutePath()); + folder.setAlbumPath(image.getPath()); + folder.getImages().add(image); + folderSource.put(folderPath, folder); + addFolder.add(folder); + } + + if (mRegisterKey.equals(folderPath)) { + addImages.add(image); + } + } + + notifyFolderAdd(addFolder); + notifyFolderUpdate(updateFolder); + notifyImageAdd(addImages); + } + + private void callDataRemoved(List images) { + List updateFolder = new ArrayList<>(); + List removeFolder = new ArrayList<>(); + List removeImages = new ArrayList<>(); + + final Map folderSource = mFolderSource; + for (Image image : images) { + File folderFile = new File(image.getPath()).getParentFile(); + String folderPath = folderFile.getAbsolutePath().toLowerCase(); + if (folderSource.containsKey(folderPath)) { + ImageFolder folder = folderSource.get(folderPath); + List folderImages = folder.getImages(); + if (folderImages.contains(image)) { + // only remove option + folderImages.remove(image); + if (folderImages.size() == 0) { + // Remove + folderSource.remove(folderPath); + removeFolder.add(folder); + } else { + // Update data remove + if (!updateFolder.contains(folder)) { + updateFolder.add(folder); + } + } + } + } + + if (mRegisterKey.equals(folderPath)) { + removeImages.add(image); + } + } + + notifyFolderUpdate(updateFolder); + notifyFolderRemove(removeFolder); + notifyImageRemove(removeImages); + } + + @Override + public void onLoaderReset(Loader loader) { + + } + + private void notifyFolderUpdate(List items) { + if (items.size() == 0) + return; + mFolderCallback.onFolderUpdated(items); + } + + private void notifyFolderAdd(List items) { + if (items.size() == 0) + return; + mFolderCallback.onFolderAdded(items); + } + + private void notifyFolderRemove(List items) { + if (items.size() == 0) + return; + mFolderCallback.onFolderRemoved(items); + } + + + private void notifyImageAdd(List items) { + if (items.size() == 0) + return; + mImageCallback.onPictureAdded(items); + } + + private void notifyImageRemove(List items) { + if (items.size() == 0) + return; + mImageCallback.onPictureRemoved(items); + } + + public void selectFolder(ImageFolder folder) { + this.mRegisterKey = folder.getPath().toLowerCase(); + } + + public interface PictureSourceCallback { + void onPictureRemoved(List images); + + void onPictureAdded(List images); + } + + public interface FolderSourceCallback { + void onFolderRemoved(List images); + + void onFolderAdded(List images); + + void onFolderUpdated(List images); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/media/PreviewerViewPager.java b/app/src/main/java/net/oschina/app/improve/media/PreviewerViewPager.java new file mode 100644 index 0000000000000000000000000000000000000000..06efcaf19bade47ec3a24fb0e292f08c067d16f9 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/media/PreviewerViewPager.java @@ -0,0 +1,69 @@ +package net.oschina.app.improve.media; + +import android.content.Context; +import android.support.v4.view.ViewPager; +import android.util.AttributeSet; +import android.view.MotionEvent; + +/** + * 适配ImagePreviewerView的使用 + * Created by thanatos on 16/8/5. + */ +public class PreviewerViewPager extends ViewPager { + + private boolean isInterceptable = false; + private boolean isTransition = false; + private int mScrollState = SCROLL_STATE_IDLE; + + public PreviewerViewPager(Context context) { + this(context, null); + } + + public PreviewerViewPager(Context context, AttributeSet attrs) { + super(context, attrs); + addOnPageChangeListener(new PageChangeListener()); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + if (mScrollState != SCROLL_STATE_IDLE) { + return super.onInterceptTouchEvent(ev); + } + + // 移动到边界改变拦截方式时 + if (isTransition) { + int action = ev.getAction(); + ev.setAction(MotionEvent.ACTION_DOWN); + super.onInterceptTouchEvent(ev); + ev.setAction(action); + isTransition = false; + } + + boolean b = false; + + int action = ev.getAction(); + + if (action == MotionEvent.ACTION_DOWN) { + isInterceptable = false; + } + + if (action != MotionEvent.ACTION_MOVE || isInterceptable) { + b = super.onInterceptTouchEvent(ev); + } + + return isInterceptable && b; + } + + public void isInterceptable(boolean b) { + if (!isInterceptable && b) isTransition = true; + this.isInterceptable = b; + } + + private class PageChangeListener extends SimpleOnPageChangeListener { + + @Override + public void onPageScrollStateChanged(int state) { + mScrollState = state; + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/media/SelectFragment.java b/app/src/main/java/net/oschina/app/improve/media/SelectFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..f11e3a2c1c90dee88f99a6d9af1701eb4ff71a7f --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/media/SelectFragment.java @@ -0,0 +1,482 @@ +package net.oschina.app.improve.media; + +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.provider.MediaStore; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.text.TextUtils; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.Toast; + +import net.oschina.app.R; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.base.fragments.BaseFragment; +import net.oschina.app.improve.media.adapter.ImageAdapter; +import net.oschina.app.improve.media.adapter.ImageFolderAdapter; +import net.oschina.app.improve.media.bean.Image; +import net.oschina.app.improve.media.bean.ImageFolder; +import net.oschina.app.improve.media.config.ImageLoaderListener; +import net.oschina.app.improve.media.config.SelectOptions; +import net.oschina.app.improve.media.contract.SelectImageContract; +import net.oschina.app.improve.media.crop.CropActivity; +import net.oschina.app.ui.empty.EmptyLayout; +import net.qiujuer.genius.ui.Ui; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import butterknife.Bind; +import butterknife.OnClick; + +/** + * 图片选择库实现界面 + * Created by huanghaibin_dev + * on 2016/7/13. + *

    + * Changed by qiujuer + * on 2016/09/01 + */ +public class SelectFragment extends BaseFragment implements SelectImageContract.View, View.OnClickListener, + ImageLoaderListener, BaseRecyclerAdapter.OnItemClickListener { + @Bind(R.id.rv_image) + RecyclerView mContentView; + @Bind(R.id.btn_title_select) + Button mSelectFolderView; + @Bind(R.id.iv_title_select) + ImageView mSelectFolderIcon; + @Bind(R.id.toolbar) + View mToolbar; + @Bind(R.id.btn_done) + Button mDoneView; + @Bind(R.id.btn_preview) + Button mPreviewView; + + @Bind(R.id.error_layout) + EmptyLayout mErrorLayout; + + private ImageFolderPopupWindow mFolderPopupWindow; + private ImageFolderAdapter mImageFolderAdapter; + private ImageAdapter mImageAdapter; + + private List mSelectedImage; + + private String mCamImageName; + private LoaderListener mCursorLoader = new LoaderListener(); + + private SelectImageContract.Operator mOperator; + + private static SelectOptions mOption; + + public static SelectFragment newInstance(SelectOptions options) { + SelectFragment fragment = new SelectFragment(); + mOption = options; + return fragment; + } + + @Override + public void onAttach(Context context) { + this.mOperator = (SelectImageContract.Operator) context; + this.mOperator.setDataView(this); + super.onAttach(context); + } + + @Override + protected int getLayoutId() { + return R.layout.fragment_select_image; + } + + @OnClick({R.id.btn_preview, R.id.icon_back, R.id.btn_title_select, R.id.btn_done}) + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.icon_back: + mOperator.onBack(); + break; + case R.id.btn_preview: + if (mSelectedImage.size() > 0) { + ImageGalleryActivity.show(getActivity(), Util.toArray(mSelectedImage), 0, false); + } + break; + case R.id.btn_title_select: + showPopupFolderList(); + break; + case R.id.btn_done: + onSelectComplete(); + break; + } + } + + @Override + protected void initWidget(View view) { + mContentView.setLayoutManager(new GridLayoutManager(getActivity(), 4)); + mContentView.addItemDecoration(new SpaceGridItemDecoration((int) Ui.dipToPx(getResources(), 1))); + mImageAdapter = new ImageAdapter(getContext(), this); + mImageFolderAdapter = new ImageFolderAdapter(getActivity()); + mImageFolderAdapter.setLoader(this); + mContentView.setAdapter(mImageAdapter); + mContentView.setItemAnimator(null); + mImageAdapter.setOnItemClickListener(this); + mErrorLayout.setOnLayoutClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING); + getLoaderManager().initLoader(0, null, mCursorLoader); + } + }); + } + + @Override + protected void initData() { + mSelectedImage = new ArrayList<>(); + + if (mOption.getSelectCount() > 1 && mOption.getSelectedImages() != null) { + List images = mOption.getSelectedImages(); + for (String s : images) { + // checkShare file exists + if (s != null && new File(s).exists()) { + Image image = new Image(); + image.setSelect(true); + image.setPath(s); + mSelectedImage.add(image); + } + } + } + getLoaderManager().initLoader(0, null, mCursorLoader); + } + + + @Override + public void onItemClick(int position, long itemId) { + if (mOption.isHasCam()) { + if (position != 0) { + handleSelectChange(position); + } else { + if (mSelectedImage.size() < mOption.getSelectCount()) { + mOperator.requestCamera(); + } else { + Toast.makeText(getActivity(), "最多只能选择 " + mOption.getSelectCount() + " 张图片", Toast.LENGTH_SHORT).show(); + } + } + } else { + handleSelectChange(position); + } + } + + private void handleSelectSizeChange(int size) { + if (size > 0) { + mPreviewView.setEnabled(true); + mDoneView.setEnabled(true); + mDoneView.setText(String.format("%s(%s)", getText(R.string.image_select_opt_done), size)); + } else { + mPreviewView.setEnabled(false); + mDoneView.setEnabled(false); + mDoneView.setText(getText(R.string.image_select_opt_done)); + } + } + + private void handleSelectChange(int position) { + Image image = mImageAdapter.getItem(position); + //如果是多选模式 + final int selectCount = mOption.getSelectCount(); + if (selectCount > 1) { + if (image.isSelect()) { + image.setSelect(false); + mSelectedImage.remove(image); + mImageAdapter.updateItem(position); + } else { + if (mSelectedImage.size() == selectCount) { + Toast.makeText(getActivity(), "最多只能选择 " + selectCount + " 张照片", Toast.LENGTH_SHORT).show(); + } else { + image.setSelect(true); + mSelectedImage.add(image); + mImageAdapter.updateItem(position); + } + } + handleSelectSizeChange(mSelectedImage.size()); + } else { + mSelectedImage.add(image); + handleResult(); + } + } + + private void handleResult() { + if (mSelectedImage.size() != 0) { + if (mOption.isCrop()) { + List selectedImage = mOption.getSelectedImages(); + selectedImage.clear(); + selectedImage.add(mSelectedImage.get(0).getPath()); + mSelectedImage.clear(); + CropActivity.show(this, mOption); + } else { + mOption.getCallback().doSelected(Util.toArray(mSelectedImage)); + getActivity().finish(); + } + } + } + + /** + * 完成选择 + */ + public void onSelectComplete() { + handleResult(); + } + + /** + * 申请相机权限成功 + */ + @Override + public void onOpenCameraSuccess() { + toOpenCamera(); + } + + + @Override + public void onCameraPermissionDenied() { + + } + + /** + * 创建弹出的相册 + */ + private void showPopupFolderList() { + if (mFolderPopupWindow == null) { + ImageFolderPopupWindow popupWindow = new ImageFolderPopupWindow(getActivity(), new ImageFolderPopupWindow.Callback() { + @Override + public void onSelect(ImageFolderPopupWindow popupWindow, ImageFolder model) { + addImagesToAdapter(model.getImages()); + mContentView.scrollToPosition(0); + popupWindow.dismiss(); + mSelectFolderView.setText(model.getName()); + } + + @Override + public void onDismiss() { + mSelectFolderIcon.setImageResource(R.mipmap.ic_arrow_bottom); + } + + @Override + public void onShow() { + mSelectFolderIcon.setImageResource(R.mipmap.ic_arrow_top); + } + }); + popupWindow.setAdapter(mImageFolderAdapter); + mFolderPopupWindow = popupWindow; + } + mFolderPopupWindow.showAsDropDown(mToolbar); + } + + /** + * 打开相机 + */ + private void toOpenCamera() { + // 判断是否挂载了SD卡 + mCamImageName = null; + String savePath = ""; + if (Util.hasSDCard()) { + savePath = Util.getCameraPath(); + File saveDir = new File(savePath); + if (!saveDir.exists()) { + saveDir.mkdirs(); + } + } + + // 没有挂载SD卡,无法保存文件 + if (TextUtils.isEmpty(savePath)) { + Toast.makeText(getActivity(), "无法保存照片,请检查SD卡是否挂载", Toast.LENGTH_LONG).show(); + return; + } + + mCamImageName = Util.getSaveImageFullName(); + File out = new File(savePath, mCamImageName); + Uri uri = Uri.fromFile(out); + + Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); + startActivityForResult(intent, + 0x03); + } + + /** + * 拍照完成通知系统添加照片 + * + * @param requestCode requestCode + * @param resultCode resultCode + * @param data data + */ + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (resultCode == AppCompatActivity.RESULT_OK) { + switch (requestCode) { + case 0x03: + if (mCamImageName == null) return; + Uri localUri = Uri.fromFile(new File(Util.getCameraPath() + mCamImageName)); + Intent localIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, localUri); + getActivity().sendBroadcast(localIntent); + break; + case 0x04: + if (data == null) return; + mOption.getCallback().doSelected(new String[]{data.getStringExtra("crop_path")}); + getActivity().finish(); + break; + } + } + } + + @Override + public void displayImage(final ImageView iv, final String path) { + getImgLoader().load(path) + .asBitmap() + .centerCrop() + .error(R.mipmap.ic_split_graph) + .into(iv); + } + + private class LoaderListener implements LoaderManager.LoaderCallbacks { + private final String[] IMAGE_PROJECTION = { + MediaStore.Images.Media.DATA, + MediaStore.Images.Media.DISPLAY_NAME, + MediaStore.Images.Media.DATE_ADDED, + MediaStore.Images.Media._ID, + MediaStore.Images.Media.MINI_THUMB_MAGIC, + MediaStore.Images.Media.BUCKET_DISPLAY_NAME}; + + @Override + public Loader onCreateLoader(int id, Bundle args) { + if (id == 0) { + //数据库光标加载器 + return new CursorLoader(getContext(), + MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_PROJECTION, + null, null, IMAGE_PROJECTION[2] + " DESC"); + } + return null; + } + + @Override + public void onLoadFinished(Loader loader, final Cursor data) { + if (data != null) { + + final ArrayList images = new ArrayList<>(); + final List imageFolders = new ArrayList<>(); + + final ImageFolder defaultFolder = new ImageFolder(); + defaultFolder.setName("全部照片"); + defaultFolder.setPath(""); + imageFolders.add(defaultFolder); + + int count = data.getCount(); + if (count > 0) { + data.moveToFirst(); + do { + String path = data.getString(data.getColumnIndexOrThrow(IMAGE_PROJECTION[0])); + String name = data.getString(data.getColumnIndexOrThrow(IMAGE_PROJECTION[1])); + long dateTime = data.getLong(data.getColumnIndexOrThrow(IMAGE_PROJECTION[2])); + int id = data.getInt(data.getColumnIndexOrThrow(IMAGE_PROJECTION[3])); + String thumbPath = data.getString(data.getColumnIndexOrThrow(IMAGE_PROJECTION[4])); + String bucket = data.getString(data.getColumnIndexOrThrow(IMAGE_PROJECTION[5])); + + Image image = new Image(); + image.setPath(path); + image.setName(name); + image.setDate(dateTime); + image.setId(id); + image.setThumbPath(thumbPath); + image.setFolderName(bucket); + + images.add(image); + + //如果是新拍的照片 + if (mCamImageName != null && mCamImageName.equals(image.getName())) { + image.setSelect(true); + mSelectedImage.add(image); + } + + //如果是被选中的图片 + if (mSelectedImage.size() > 0) { + for (Image i : mSelectedImage) { + if (i.getPath().equals(image.getPath())) { + image.setSelect(true); + } + } + } + + File imageFile = new File(path); + File folderFile = imageFile.getParentFile(); + ImageFolder folder = new ImageFolder(); + folder.setName(folderFile.getName()); + folder.setPath(folderFile.getAbsolutePath()); + if (!imageFolders.contains(folder)) { + folder.getImages().add(image); + folder.setAlbumPath(image.getPath());//默认相册封面 + imageFolders.add(folder); + } else { + // 更新 + ImageFolder f = imageFolders.get(imageFolders.indexOf(folder)); + f.getImages().add(image); + } + + + } while (data.moveToNext()); + } + addImagesToAdapter(images); + defaultFolder.getImages().addAll(images); + if (mOption.isHasCam()) { + defaultFolder.setAlbumPath(images.size() > 1 ? images.get(1).getPath() : null); + } else { + defaultFolder.setAlbumPath(images.size() > 0 ? images.get(0).getPath() : null); + } + mImageFolderAdapter.resetItem(imageFolders); + + //删除掉不存在的,在于用户选择了相片,又去相册删除 + if (mSelectedImage.size() > 0) { + List rs = new ArrayList<>(); + for (Image i : mSelectedImage) { + File f = new File(i.getPath()); + if (!f.exists()) { + rs.add(i); + } + } + mSelectedImage.removeAll(rs); + } + + // If add new mCamera picture, and we only need one picture, we result it. + if (mOption.getSelectCount() == 1 && mCamImageName != null) { + handleResult(); + } + + handleSelectSizeChange(mSelectedImage.size()); + mErrorLayout.setErrorType(EmptyLayout.HIDE_LAYOUT); + } + } + + @Override + public void onLoaderReset(Loader loader) { + + } + } + + private void addImagesToAdapter(ArrayList images) { + mImageAdapter.clear(); + if (mOption.isHasCam()) { + Image cam = new Image(); + mImageAdapter.addItem(cam); + } + mImageAdapter.addAll(images); + } + + @Override + public void onDestroy() { + mOption = null; + super.onDestroy(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/media/SelectImageActivity.java b/app/src/main/java/net/oschina/app/improve/media/SelectImageActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..f2ffe9d961c001b7503aad1f2473ca100014c5ab --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/media/SelectImageActivity.java @@ -0,0 +1,168 @@ +package net.oschina.app.improve.media; + +import android.Manifest; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.provider.Settings; +import android.support.annotation.NonNull; +import android.support.v4.app.Fragment; + +import net.oschina.app.R; +import net.oschina.app.improve.base.activities.BaseBackActivity; +import net.oschina.app.improve.media.config.SelectOptions; +import net.oschina.app.improve.media.contract.SelectImageContract; +import net.oschina.app.improve.utils.DialogHelper; + +import java.util.List; + +import pub.devrel.easypermissions.AfterPermissionGranted; +import pub.devrel.easypermissions.EasyPermissions; + +/** + * Created by huanghaibin_dev + * on 2016/7/13. + *

    + * Changed by qiujuer + * on 2016/09/01 + */ +@SuppressWarnings("All") +public class SelectImageActivity extends BaseBackActivity implements EasyPermissions.PermissionCallbacks, SelectImageContract.Operator { + private static final int RC_CAMERA_PERM = 0x03; + private static final int RC_EXTERNAL_STORAGE = 0x04; + public static final String KEY_CONFIG = "config"; + + private static SelectOptions mOption; + private SelectImageContract.View mView; + + public static void show(Context context, SelectOptions options) { + mOption = options; + context.startActivity(new Intent(context, SelectImageActivity.class)); + } + + @Override + protected int getContentView() { + return R.layout.activity_select_image; + } + + @Override + protected void initWidget() { + super.initWidget(); + requestExternalStorage(); + } + + @AfterPermissionGranted(RC_CAMERA_PERM) + @Override + public void requestCamera() { + if (EasyPermissions.hasPermissions(this, Manifest.permission.CAMERA)) { + if (mView != null) { + mView.onOpenCameraSuccess(); + } + } else { + EasyPermissions.requestPermissions(this, "", RC_CAMERA_PERM, Manifest.permission.CAMERA); + } + } + + @AfterPermissionGranted(RC_EXTERNAL_STORAGE) + @Override + public void requestExternalStorage() { + if (EasyPermissions.hasPermissions(this, Manifest.permission.READ_EXTERNAL_STORAGE)) { + if (mView == null) { + handleView(); + } + } else { + EasyPermissions.requestPermissions(this, "", RC_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE); + } + } + + @Override + public void onBack() { + onSupportNavigateUp(); + } + + @Override + public void setDataView(SelectImageContract.View view) { + mView = view; + } + + @Override + protected void onDestroy() { + mOption = null; + super.onDestroy(); + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); + } + + + @Override + public boolean shouldShowRequestPermissionRationale(String permission) { + return false; + } + + @Override + public void onPermissionsGranted(int requestCode, List perms) { + + } + + @Override + public void onPermissionsDenied(int requestCode, List perms) { + if (requestCode == RC_EXTERNAL_STORAGE) { + removeView(); + DialogHelper.getConfirmDialog(this, "", "没有权限, 你需要去设置中开启读取手机存储权限.", "去设置", "取消", false, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + startActivity(new Intent(Settings.ACTION_APPLICATION_SETTINGS)); + finish(); + } + }, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }).show(); + } else { + if (mView != null) + mView.onCameraPermissionDenied(); + DialogHelper.getConfirmDialog(this, "", "没有权限, 你需要去设置中开启相机权限.", "去设置", "取消", false, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + startActivity(new Intent(Settings.ACTION_APPLICATION_SETTINGS)); + } + }, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + } + }).show(); + } + } + + private void removeView() { + SelectImageContract.View view = mView; + if (view == null) + return; + try { + getSupportFragmentManager() + .beginTransaction() + .remove((Fragment) view) + .commitNowAllowingStateLoss(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void handleView() { + try { + //Fragment fragment = Fragment.instantiate(this, SelectFragment.class.getName()); + getSupportFragmentManager() + .beginTransaction() + .replace(R.id.fl_content, SelectFragment.newInstance(mOption)) + .commitNowAllowingStateLoss(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/media/SpaceGridItemDecoration.java b/app/src/main/java/net/oschina/app/improve/media/SpaceGridItemDecoration.java new file mode 100644 index 0000000000000000000000000000000000000000..d023ace9155e87fde54d0800a1a84dde61e5220a --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/media/SpaceGridItemDecoration.java @@ -0,0 +1,26 @@ +package net.oschina.app.improve.media; + +import android.graphics.Rect; +import android.support.v7.widget.RecyclerView; +import android.view.View; + +/** + * Created by huanghaibin + * on 16-5-9. + */ +public class SpaceGridItemDecoration extends RecyclerView.ItemDecoration { + private int space; + + public SpaceGridItemDecoration(int space) { + this.space = space; + } + + @Override + public void getItemOffsets(Rect outRect, View view, + RecyclerView parent, RecyclerView.State state) { + outRect.left = space; + outRect.right = space; + outRect.bottom = space; + outRect.top = space; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/media/Util.java b/app/src/main/java/net/oschina/app/improve/media/Util.java new file mode 100644 index 0000000000000000000000000000000000000000..ee8c1416c8d4a351afbb9f9ab07a5f4e344eeb20 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/media/Util.java @@ -0,0 +1,108 @@ +package net.oschina.app.improve.media; + +import android.content.Context; +import android.os.Environment; +import android.view.Display; +import android.view.WindowManager; + +import net.oschina.app.improve.media.bean.Image; + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * 选择图片库相关工具类 + */ +@SuppressWarnings("All") +public class Util { + + public static boolean hasSDCard() { + String status = Environment.getExternalStorageState(); + if (!status.equals(Environment.MEDIA_MOUNTED)) { + return false; + } + return true; + } + + public static String getCameraPath() { + return Environment.getExternalStorageDirectory().getAbsolutePath() + "/DCIM/Camera/";// filePath:/sdcard/ + } + + public static String getSaveImageFullName() { + return "IMG_" + new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()) + ".jpg";// 照片命名 + } + + public static ArrayList toArrayList(List images) { + ArrayList strings = new ArrayList<>(); + for (Image i : images) { + strings.add(i.getPath()); + } + return strings; + } + + public static String[] toArray(List images) { + if (images == null) + return null; + int len = images.size(); + if (len == 0) + return null; + + String[] strings = new String[len]; + int i = 0; + for (Image image : images) { + strings[i] = image.getPath(); + i++; + } + return strings; + } + + /** + * 获得屏幕的宽度 + * + * @param context context + * @return width + */ + public static int getScreenWidth(Context context) { + WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + Display display = manager.getDefaultDisplay(); + return display.getWidth(); + } + + /** + * 获得屏幕的高度 + * + * @param context context + * @return height + */ + public static int getScreenHeight(Context context) { + WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + Display display = manager.getDefaultDisplay(); + return display.getHeight(); + } + + /** + * dp转px + * + * @param context context + * @param dpValue dp + * @return px + */ + public static int dipTopx(Context context, float dpValue) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (dpValue * scale + 0.5f); + } + + /** + * px转dp + * + * @param context context + * @param pxValue px + * @return dp + */ + public static float pxTodip(Context context, float pxValue) { + final float scale = context.getResources().getDisplayMetrics().density; + return pxValue / scale + 0.5f; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/media/adapter/ImageAdapter.java b/app/src/main/java/net/oschina/app/improve/media/adapter/ImageAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..982c4a2729dd4bf3ba3337a0e8dbd4b4e6aca69e --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/media/adapter/ImageAdapter.java @@ -0,0 +1,86 @@ +package net.oschina.app.improve.media.adapter; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +import com.bumptech.glide.Glide; + +import net.oschina.app.R; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.media.bean.Image; +import net.oschina.app.improve.media.config.ImageLoaderListener; + + +/** + * 图片列表界面适配器 + */ +public class ImageAdapter extends BaseRecyclerAdapter { + private ImageLoaderListener loader; + + public ImageAdapter(Context context, ImageLoaderListener loader) { + super(context, NEITHER); + this.loader = loader; + } + + @Override + public int getItemViewType(int position) { + Image image = getItem(position); + if (image.getId() == 0) + return 0; + return 1; + } + + @Override + public void onViewRecycled(RecyclerView.ViewHolder holder) { + if (holder instanceof ImageViewHolder) { + ImageViewHolder h = (ImageViewHolder) holder; + Glide.clear(h.mImageView); + } + } + + @Override + protected RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type) { + if (type == 0) + return new CamViewHolder(mInflater.inflate(R.layout.item_list_cam, parent, false)); + return new ImageViewHolder(mInflater.inflate(R.layout.item_list_image, parent, false)); + } + + @Override + protected void onBindDefaultViewHolder(RecyclerView.ViewHolder holder, Image item, int position) { + if (item.getId() != 0) { + ImageViewHolder h = (ImageViewHolder) holder; + h.mCheckView.setSelected(item.isSelect()); + h.mMaskView.setVisibility(item.isSelect() ? View.VISIBLE : View.GONE); + + // Show gif mask + h.mGifMask.setVisibility(item.getPath().toLowerCase().endsWith("gif") ? + View.VISIBLE : View.GONE); + + loader.displayImage(h.mImageView, item.getPath()); + } + } + + private static class CamViewHolder extends RecyclerView.ViewHolder { + CamViewHolder(View itemView) { + super(itemView); + } + } + + private static class ImageViewHolder extends RecyclerView.ViewHolder { + ImageView mImageView; + ImageView mCheckView; + ImageView mGifMask; + View mMaskView; + + ImageViewHolder(View itemView) { + super(itemView); + mImageView = (ImageView) itemView.findViewById(R.id.iv_image); + mCheckView = (ImageView) itemView.findViewById(R.id.cb_selected); + mMaskView = itemView.findViewById(R.id.lay_mask); + mGifMask = (ImageView) itemView.findViewById(R.id.iv_is_gif); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/media/adapter/ImageFolderAdapter.java b/app/src/main/java/net/oschina/app/improve/media/adapter/ImageFolderAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..e17d3cdbf25310cf46af737af93be13ab585834f --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/media/adapter/ImageFolderAdapter.java @@ -0,0 +1,61 @@ +package net.oschina.app.improve.media.adapter; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import net.oschina.app.R; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.media.bean.ImageFolder; +import net.oschina.app.improve.media.config.ImageLoaderListener; + + +/** + * Created by huanghaibin_dev + * on 2016/7/13. + *

    + * Changed by qiujuer + * on 2016/09/01 + */ + +public class ImageFolderAdapter extends BaseRecyclerAdapter { + private ImageLoaderListener loader; + + public ImageFolderAdapter(Context context) { + super(context, NEITHER); + } + + @Override + protected RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type) { + return new FolderViewHolder(mInflater.inflate(R.layout.item_list_folder, parent, false)); + } + + @Override + protected void onBindDefaultViewHolder(RecyclerView.ViewHolder holder, ImageFolder item, int position) { + FolderViewHolder h = (FolderViewHolder) holder; + h.tv_name.setText(item.getName()); + h.tv_size.setText(String.format("(%s)", item.getImages().size())); + if (loader != null) { + loader.displayImage(h.iv_image, item.getAlbumPath()); + } + } + + public void setLoader(ImageLoaderListener loader) { + this.loader = loader; + } + + private static class FolderViewHolder extends RecyclerView.ViewHolder { + ImageView iv_image; + TextView tv_name, tv_size; + + public FolderViewHolder(View itemView) { + super(itemView); + iv_image = (ImageView) itemView.findViewById(R.id.iv_folder); + tv_name = (TextView) itemView.findViewById(R.id.tv_folder_name); + tv_size = (TextView) itemView.findViewById(R.id.tv_size); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/media/bean/Image.java b/app/src/main/java/net/oschina/app/improve/media/bean/Image.java new file mode 100644 index 0000000000000000000000000000000000000000..a881a9c01931bce05b3540d9f4997e0e5eeb383f --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/media/bean/Image.java @@ -0,0 +1,82 @@ +package net.oschina.app.improve.media.bean; + +import java.io.Serializable; + +/** + * Created by huanghaibin_dev + * on 2016/7/11. + */ + +public class Image implements Serializable { + private int id; + private String path; + private String thumbPath; + private boolean isSelect; + private String folderName; + private String name; + private long date; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public String getThumbPath() { + return thumbPath; + } + + public void setThumbPath(String thumbPath) { + this.thumbPath = thumbPath; + } + + public boolean isSelect() { + return isSelect; + } + + public void setSelect(boolean select) { + isSelect = select; + } + + public String getFolderName() { + return folderName; + } + + public void setFolderName(String folderName) { + this.folderName = folderName; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public long getDate() { + return date; + } + + public void setDate(long date) { + this.date = date; + } + + @Override + public boolean equals(Object o) { + if (o instanceof Image) { + return this.path.equals(((Image) o).getPath()); + } + return false; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/media/bean/ImageFolder.java b/app/src/main/java/net/oschina/app/improve/media/bean/ImageFolder.java new file mode 100644 index 0000000000000000000000000000000000000000..85f94627337a4eb5cd0295e61f76494fc6b33331 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/media/bean/ImageFolder.java @@ -0,0 +1,54 @@ +package net.oschina.app.improve.media.bean; + +import java.io.Serializable; +import java.util.ArrayList; + +/** + * Created by huanghaibin_dev + * on 2016/7/11. + */ +public class ImageFolder implements Serializable { + private String name; + private String path; + private String albumPath; + private ArrayList images = new ArrayList<>(); + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public ArrayList getImages() { + return images; + } + + public String getAlbumPath() { + return albumPath; + } + + public void setAlbumPath(String albumPath) { + this.albumPath = albumPath; + } + + @Override + public boolean equals(Object o) { + if (o != null && o instanceof ImageFolder) { + if (((ImageFolder) o).getPath() == null && path != null) + return false; + String oPath = ((ImageFolder) o).getPath().toLowerCase(); + return oPath.equals(this.path.toLowerCase()); + } + return false; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/media/config/ImageLoaderListener.java b/app/src/main/java/net/oschina/app/improve/media/config/ImageLoaderListener.java new file mode 100644 index 0000000000000000000000000000000000000000..14f324d3dd84feea0429d5f1aca32afe2753b1e9 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/media/config/ImageLoaderListener.java @@ -0,0 +1,12 @@ +package net.oschina.app.improve.media.config; + +import android.widget.ImageView; + +/** + * 暴露一个图片加载器 + * Created by huanghaibin_dev + * on 2016/7/13. + */ +public interface ImageLoaderListener { + void displayImage(ImageView iv, String path); +} diff --git a/app/src/main/java/net/oschina/app/improve/media/config/SelectOptions.java b/app/src/main/java/net/oschina/app/improve/media/config/SelectOptions.java new file mode 100644 index 0000000000000000000000000000000000000000..3053984b260a927775de121ded3eedf4473576a9 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/media/config/SelectOptions.java @@ -0,0 +1,121 @@ +package net.oschina.app.improve.media.config; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Created by haibin + * on 2016/12/5. + */ + +public final class SelectOptions { + private boolean isCrop; + private int mCropWidth, mCropHeight; + private Callback mCallback; + private boolean hasCam; + private int mSelectCount; + private List mSelectedImages; + + private SelectOptions() { + + } + + public boolean isCrop() { + return isCrop; + } + + public int getCropWidth() { + return mCropWidth; + } + + public int getCropHeight() { + return mCropHeight; + } + + public Callback getCallback() { + return mCallback; + } + + public boolean isHasCam() { + return hasCam; + } + + public int getSelectCount() { + return mSelectCount; + } + + public List getSelectedImages() { + return mSelectedImages; + } + + public static class Builder { + private boolean isCrop; + private int cropWidth, cropHeight; + private Callback callback; + private boolean hasCam; + private int selectCount; + private List selectedImages; + + public Builder() { + selectCount = 1; + hasCam = true; + selectedImages = new ArrayList<>(); + } + + public Builder setCrop(int cropWidth, int cropHeight) { + if (cropWidth <= 0 || cropHeight <= 0) + throw new IllegalArgumentException("cropWidth or cropHeight mast be greater than 0 "); + this.isCrop = true; + this.cropWidth = cropWidth; + this.cropHeight = cropHeight; + return this; + } + + public Builder setCallback(Callback callback) { + this.callback = callback; + return this; + } + + public Builder setHasCam(boolean hasCam) { + this.hasCam = hasCam; + return this; + } + + public Builder setSelectCount(int selectCount) { + if (selectCount <= 0) + throw new IllegalArgumentException("selectCount mast be greater than 0 "); + this.selectCount = selectCount; + return this; + } + + public Builder setSelectedImages(List selectedImages) { + if (selectedImages == null || selectedImages.size() == 0) return this; + this.selectedImages.addAll(selectedImages); + return this; + } + + public Builder setSelectedImages(String[] selectedImages) { + if (selectedImages == null || selectedImages.length == 0) return this; + if (this.selectedImages == null) this.selectedImages = new ArrayList<>(); + this.selectedImages.addAll(Arrays.asList(selectedImages)); + return this; + } + + public SelectOptions build() { + SelectOptions options = new SelectOptions(); + options.hasCam = hasCam; + options.isCrop = isCrop; + options.mCropHeight = cropHeight; + options.mCropWidth = cropWidth; + options.mCallback = callback; + options.mSelectCount = selectCount; + options.mSelectedImages = selectedImages; + return options; + } + } + + public interface Callback { + void doSelected(String[] images); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/media/contract/SelectImageContract.java b/app/src/main/java/net/oschina/app/improve/media/contract/SelectImageContract.java new file mode 100644 index 0000000000000000000000000000000000000000..a316e7bd7aace122cd27d9a7aa6fe2924f1d954f --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/media/contract/SelectImageContract.java @@ -0,0 +1,25 @@ +package net.oschina.app.improve.media.contract; + +/** + * 图片选择器建立契约关系,将权限操作放在Activity,具体数据放在Fragment + * Created by huanghaibin_dev + * on 2016/7/15. + */ +public interface SelectImageContract { + interface Operator { + void requestCamera(); + + void requestExternalStorage(); + + void onBack(); + + void setDataView(View view); + } + + interface View { + + void onOpenCameraSuccess(); + + void onCameraPermissionDenied(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/media/crop/CropActivity.java b/app/src/main/java/net/oschina/app/improve/media/crop/CropActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..acfd9b058769c1b088fd331f618e543fa8d4fb9c --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/media/crop/CropActivity.java @@ -0,0 +1,92 @@ +package net.oschina.app.improve.media.crop; + +import android.content.Intent; +import android.graphics.Bitmap; +import android.support.v4.app.Fragment; +import android.view.View; +import android.view.WindowManager; + +import net.oschina.app.R; +import net.oschina.app.improve.base.activities.BaseActivity; +import net.oschina.app.improve.media.config.SelectOptions; +import net.oschina.common.utils.StreamUtil; + +import java.io.FileOutputStream; + +import butterknife.OnClick; + +/** + * Created by haibin + * on 2016/12/2. + */ + +public class CropActivity extends BaseActivity implements View.OnClickListener { + private CropLayout mCropLayout; + private static SelectOptions mOption; + + public static void show(Fragment fragment, SelectOptions options) { + Intent intent = new Intent(fragment.getActivity(), CropActivity.class); + mOption = options; + fragment.startActivityForResult(intent, 0x04); + } + + @Override + protected int getContentView() { + return R.layout.activity_crop; + } + + @Override + protected void initWidget() { + super.initWidget(); + setTitle(""); + getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT); + mCropLayout = (CropLayout) findViewById(R.id.cropLayout); + } + + @Override + protected void initData() { + super.initData(); + getImageLoader().load(mOption.getSelectedImages().get(0)).into(mCropLayout.getImageView()); + mCropLayout.setCropWidth(mOption.getCropWidth()); + mCropLayout.setCropHeight(mOption.getCropHeight()); + mCropLayout.start(); + } + + @OnClick({R.id.tv_crop, R.id.tv_cancel}) + @Override + public void onClick(View view) { + switch (view.getId()) { + case R.id.tv_crop: + Bitmap bitmap = null; + FileOutputStream os = null; + try { + bitmap = mCropLayout.cropBitmap(); + String path = getFilesDir() + "/crop.jpg"; + os = new FileOutputStream(path); + bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os); + os.flush(); + os.close(); + + Intent intent = new Intent(); + intent.putExtra("crop_path", path); + setResult(RESULT_OK, intent); + finish(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (bitmap != null) bitmap.recycle(); + StreamUtil.close(os); + } + break; + case R.id.tv_cancel: + finish(); + break; + } + } + + @Override + protected void onDestroy() { + mOption = null; + super.onDestroy(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/media/crop/CropDrawable.java b/app/src/main/java/net/oschina/app/improve/media/crop/CropDrawable.java new file mode 100644 index 0000000000000000000000000000000000000000..b9d4e59d51518a2252da39176cb8ec9bd255293b --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/media/crop/CropDrawable.java @@ -0,0 +1,121 @@ +package net.oschina.app.improve.media.crop; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; + +import net.oschina.app.improve.media.Util; + +/** + * Created by haibin + * on 2016/12/1. + */ +@SuppressWarnings("ALL") +public class CropDrawable extends Drawable { + private Context mContext; + private int offset = 50; + + private Paint mCirclePaint = new Paint();//圆角 + private Paint mLinePaint = new Paint();//正方形框 + + private int mCropWidth = 800, mCropHeight = 800; + + private static final int RADIUS = 20; + + private int mLeft, mRight, mTop, mBottom; + + public CropDrawable(Context mContext) { + this.mContext = mContext; + initPaint(); + } + + private void initPaint() { + mLinePaint.setARGB(200, 50, 50, 50); + mLinePaint.setStrokeWidth(2f); + mLinePaint.setStyle(Paint.Style.STROKE); + mLinePaint.setAntiAlias(true); + mLinePaint.setColor(Color.WHITE); + + mCirclePaint.setColor(Color.WHITE); + mCirclePaint.setStyle(Paint.Style.FILL);//实心圆 + mCirclePaint.setAntiAlias(true); + } + + @Override + public void draw(Canvas canvas) { + int width = Util.getScreenWidth(mContext); + int height = Util.getScreenHeight(mContext); + mLeft = (width - mCropWidth) / 2; + mTop = (height - mCropHeight) / 2; + mRight = (width + mCropWidth) / 2; + mBottom = (height + mCropHeight) / 2; + Rect rect = new Rect(mLeft, mTop, mRight, mBottom); + canvas.drawRect(rect, mLinePaint); + canvas.drawCircle(rect.left, rect.top + mCropHeight, RADIUS, mCirclePaint); + canvas.drawCircle(rect.right, rect.top + mCropHeight, RADIUS, mCirclePaint); + canvas.drawCircle(rect.left, rect.bottom - mCropHeight, RADIUS, mCirclePaint); + canvas.drawCircle(rect.right, rect.bottom - mCropHeight, RADIUS, mCirclePaint); + } + + @Override + public void setAlpha(int alpha) { + + } + + public void offset(int x, int y) { + getBounds().offset(x, y); + } + + @Override + public void setBounds(Rect bounds) { + super.setBounds(new Rect(mLeft, mTop, mRight, mBottom)); + } + + @Override + public void setColorFilter(ColorFilter colorFilter) { + + } + + @Override + public int getOpacity() { + return PixelFormat.UNKNOWN; + } + + public void setRegion(Rect rect) { + int width = Util.getScreenWidth(mContext); + int height = Util.getScreenHeight(mContext); + rect.set((width - mCropWidth) / 2, (height - mCropHeight) / 2, (width + mCropWidth) / 2, (height + mCropHeight) / 2); + } + + public int getLeft() { + return mLeft; + } + + + public int getRight() { + return mRight; + } + + + public int getTop() { + return mCropHeight; + } + + + public int getBottom() { + return mBottom; + } + + public void setCropWidth(int mCropWidth) { + this.mCropWidth = mCropWidth; + } + + public void setCropHeight(int mCropHeight) { + this.mCropHeight = mCropHeight; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/media/crop/CropFloatView.java b/app/src/main/java/net/oschina/app/improve/media/crop/CropFloatView.java new file mode 100644 index 0000000000000000000000000000000000000000..b1e700c4673a948a98247745e51d5b0b2cb4c203 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/media/crop/CropFloatView.java @@ -0,0 +1,65 @@ +package net.oschina.app.improve.media.crop; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Rect; +import android.graphics.Region; +import android.view.View; + +/** + * Created by haibin + * on 2016/12/2. + */ + +public class CropFloatView extends View { + private int mCropWidth;//设置裁剪宽度 + private int mCropHeight;//设置裁剪高度 + + private int mHOffset;//水平偏移量 + private int mVOffset;//垂直偏移量 + + private CropDrawable mCropDrawable; + private Rect mFloatRect = new Rect(); + private boolean isCrop; + + public CropFloatView(Context context) { + super(context); + mCropDrawable = new CropDrawable(context); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + cropDrawable(); + canvas.save(); + canvas.clipRect(mFloatRect, Region.Op.DIFFERENCE); + canvas.drawColor(Color.parseColor("#a0000000")); + canvas.restore(); + mCropDrawable.draw(canvas); + } + + private void cropDrawable() { + if (isCrop) return; + mCropDrawable.setRegion(mFloatRect); + isCrop = true; + } + + public void setCropWidth(int mCropWidth) { + this.mCropWidth = mCropWidth; + mCropDrawable.setCropWidth(mCropWidth); + } + + public void setCropHeight(int mCropHeight) { + this.mCropHeight = mCropHeight; + mCropDrawable.setCropHeight(mCropHeight); + } + + public void setHOffset(int mHOffset) { + this.mHOffset = mHOffset; + } + + public void setVOffset(int mVOffset) { + this.mVOffset = mVOffset; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/media/crop/CropLayout.java b/app/src/main/java/net/oschina/app/improve/media/crop/CropLayout.java new file mode 100644 index 0000000000000000000000000000000000000000..f75ccdde52a7418646e741d652dbf49bdf41b640 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/media/crop/CropLayout.java @@ -0,0 +1,65 @@ +package net.oschina.app.improve.media.crop; + +import android.content.Context; +import android.graphics.Bitmap; +import android.util.AttributeSet; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import net.oschina.app.improve.media.Util; + +/** + * Created by haibin + * on 2016/12/2. + */ +@SuppressWarnings("unused") +public class CropLayout extends FrameLayout { + private int mCropWidth = 500;//设置裁剪宽度 + private int mCropHeight = 500;//设置裁剪高度 + + private ZoomImageView mZoomImageView; + private CropFloatView mCropView; + + public CropLayout(Context context, AttributeSet attrs) { + super(context, attrs); + mZoomImageView = new ZoomImageView(context); + mCropView = new CropFloatView(context); + ViewGroup.LayoutParams lp = new LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT); + this.addView(mZoomImageView, lp); + this.addView(mCropView, lp); + } + + public ZoomImageView getImageView() { + return mZoomImageView; + } + + + public Bitmap cropBitmap() { + return mZoomImageView.cropBitmap(); + } + + public void setCropWidth(int mCropWidth) { + this.mCropWidth = mCropWidth; + mCropView.setCropWidth(mCropWidth); + mZoomImageView.setCropWidth(mCropWidth); + } + + public void setCropHeight(int mCropHeight) { + this.mCropHeight = mCropHeight; + mCropView.setCropHeight(mCropHeight); + mZoomImageView.setCropHeight(mCropHeight); + } + + public void start() { + int height = Util.getScreenHeight(getContext()); + int width = Util.getScreenWidth(getContext()); + int mHOffset = (width - mCropWidth) / 2; + int mVOffset = (height - mCropHeight) / 2; + mZoomImageView.setHOffset(mHOffset); + mZoomImageView.setVOffset(mVOffset); + mCropView.setHOffset(mHOffset); + mCropView.setVOffset(mVOffset); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/media/crop/ZoomImageView.java b/app/src/main/java/net/oschina/app/improve/media/crop/ZoomImageView.java new file mode 100644 index 0000000000000000000000000000000000000000..866ad745da1da414615c768d7c0f41afe26dec6b --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/media/crop/ZoomImageView.java @@ -0,0 +1,366 @@ +package net.oschina.app.improve.media.crop; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.GestureDetector; +import android.view.GestureDetector.SimpleOnGestureListener; +import android.view.MotionEvent; +import android.view.ScaleGestureDetector; +import android.view.ScaleGestureDetector.OnScaleGestureListener; +import android.view.View; +import android.view.View.OnTouchListener; +import android.view.ViewTreeObserver; +import android.widget.ImageView; + +/** + * Created by haibin + * on 2016/12/2. + */ +public class ZoomImageView extends ImageView implements + OnScaleGestureListener, OnTouchListener, + ViewTreeObserver.OnGlobalLayoutListener { + + private int mCropWidth;//设置裁剪宽度 + private int mCropHeight;//设置裁剪高度 + + private int mOffset = 0; + private int mVOffset = 0; + + private float SCALE_MAX = 4.0f; + private float SCALE_MID = 2.0f; + + private float mScale = 1.0f; + private boolean isFirst = true; + + private final float[] mMatrixValues = new float[9]; + + private ScaleGestureDetector mScaleGestureDetector = null; + private Matrix mScaleMatrix = new Matrix(); + + private GestureDetector mGestureDetector; + private boolean isAutoScale; + + private boolean isInit; + + private float mLastX; + private float mLastY; + + private boolean isCanDrag; + private int lastPointerCount; + + public ZoomImageView(Context context) { + this(context, null); + } + + public ZoomImageView(Context context, AttributeSet attrs) { + super(context, attrs); + setScaleType(ScaleType.MATRIX); + mGestureDetector = new GestureDetector(context, + new SimpleOnGestureListener() { + @Override + public boolean onDoubleTap(MotionEvent e) { + if (isAutoScale) + return true; + float x = e.getX(); + float y = e.getY(); + if (getScale() < SCALE_MID) { + postDelayed(new ScaleRunnable(SCALE_MID, x, y), 16); + isAutoScale = true; + } else { + postDelayed(new ScaleRunnable(mScale, x, y), 16); + isAutoScale = true; + } + return true; + } + }); + mScaleGestureDetector = new ScaleGestureDetector(context, this); + this.setOnTouchListener(this); + } + + private class ScaleRunnable implements Runnable { + static final float BIGGER = 1.07f; + static final float SMALLER = 0.93f; + private float mTargetScale; + private float mScale; + private float x; + private float y; + + ScaleRunnable(float targetScale, float x, float y) { + this.mTargetScale = targetScale; + this.x = x; + this.y = y; + if (getScale() < mTargetScale) { + mScale = BIGGER; + } else { + mScale = SMALLER; + } + + } + + @Override + public void run() { + mScaleMatrix.postScale(mScale, mScale, x, y); + checkBorder(); + setImageMatrix(mScaleMatrix); + + final float currentScale = getScale(); + if (((mScale > 1f) && (currentScale < mTargetScale)) || ((mScale < 1f) && (mTargetScale < currentScale))) { + postDelayed(this, 16); + } else { + final float deltaScale = mTargetScale / currentScale; + mScaleMatrix.postScale(deltaScale, deltaScale, x, y); + checkBorder(); + setImageMatrix(mScaleMatrix); + isAutoScale = false; + } + } + } + + @Override + public boolean onScale(ScaleGestureDetector detector) { + float scale = getScale(); + float scaleFactor = detector.getScaleFactor(); + + if (getDrawable() == null) + return true; + if ((scale < SCALE_MAX && scaleFactor > 1.0f) + || (scale > mScale && scaleFactor < 1.0f)) { + if (scaleFactor * scale < mScale) { + scaleFactor = mScale / scale; + } + if (scaleFactor * scale > SCALE_MAX) { + scaleFactor = SCALE_MAX / scale; + } + mScaleMatrix.postScale(scaleFactor, scaleFactor, + detector.getFocusX(), detector.getFocusY()); + checkBorder(); + setImageMatrix(mScaleMatrix); + } + return true; + + } + + private RectF getMatrixRectF() { + Matrix matrix = mScaleMatrix; + RectF rect = new RectF(); + Drawable d = getDrawable(); + if (null != d) { + rect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight()); + matrix.mapRect(rect); + } + return rect; + } + + @Override + public boolean onScaleBegin(ScaleGestureDetector detector) { + return true; + } + + @Override + public void onScaleEnd(ScaleGestureDetector detector) { + } + + @Override + public boolean onTouch(View v, MotionEvent event) { + + if (mGestureDetector.onTouchEvent(event)) + return true; + mScaleGestureDetector.onTouchEvent(event); + + float x = 0, y = 0; + final int pointerCount = event.getPointerCount(); + for (int i = 0; i < pointerCount; i++) { + x += event.getX(i); + y += event.getY(i); + } + x = x / pointerCount; + y = y / pointerCount; + + if (pointerCount != lastPointerCount) { + isCanDrag = false; + mLastX = x; + mLastY = y; + } + + lastPointerCount = pointerCount; + switch (event.getAction()) { + case MotionEvent.ACTION_MOVE: + float dx = x - mLastX; + float dy = y - mLastY; + + if (!isCanDrag) { + isCanDrag = isCanDrag(dx, dy); + } + if (isCanDrag) { + if (getDrawable() != null) { + + RectF rectF = getMatrixRectF(); + if (rectF.width() <= getWidth() - mOffset * 2) { + dx = 0; + } + if (rectF.height() <= getHeight() - mVOffset * 2) { + dy = 0; + } + mScaleMatrix.postTranslate(dx, dy); + checkBorder(); + setImageMatrix(mScaleMatrix); + } + } + mLastX = x; + mLastY = y; + break; + + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + lastPointerCount = 0; + break; + } + + return true; + } + + public final float getScale() { + mScaleMatrix.getValues(mMatrixValues); + return mMatrixValues[Matrix.MSCALE_X]; + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + getViewTreeObserver().addOnGlobalLayoutListener(this); + } + + @SuppressWarnings("deprecation") + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + mScaleMatrix = null; + getViewTreeObserver().removeGlobalOnLayoutListener(this); + } + + @Override + protected boolean setFrame(int l, int t, int r, int b) { + if (isInit) return false; + boolean change = super.setFrame(l, t, r, b); + Drawable drawable = getDrawable(); + if (drawable == null) return false; + int boundWidth = drawable.getBounds().width(); + int boundHeight = drawable.getBounds().height(); + if (boundWidth > mCropWidth || boundHeight > mCropHeight) return false; + int width = getWidth(); + int height = getHeight(); + mScale = (float) width / boundWidth; + isInit = true; + postDelayed(new ScaleRunnable(mScale, width / 2, height / 2), 50); + isAutoScale = false; + return change; + } + + + @Override + public void onGlobalLayout() { + if (isFirst) { + Drawable d = getDrawable(); + if (d == null) + return; + mVOffset = (getHeight() - (getWidth() - 2 * mOffset)) / 2; + + int width = getWidth(); + int height = getHeight(); + + int dw = d.getIntrinsicWidth(); + int dh = d.getIntrinsicHeight(); + float scale = 1.0f; + if (dw < getWidth() - mOffset * 2 + && dh > getHeight() - mVOffset * 2) { + scale = (getWidth() * 1.0f - mOffset * 2) / dw; + } + + if (dh < getHeight() - mVOffset * 2 + && dw > getWidth() - mOffset * 2) { + scale = (getHeight() * 1.0f - mVOffset * 2) / dh; + } + + if (dw < getWidth() - mOffset * 2 + && dh < getHeight() - mVOffset * 2) { + float scaleW = (getWidth() * 1.0f - mOffset * 2) + / dw; + float scaleH = (getHeight() * 1.0f - mVOffset * 2) / dh; + scale = Math.max(scaleW, scaleH); + } + + mScale = scale; + SCALE_MID = mScale * 2; + SCALE_MAX = mScale * 4; + mScaleMatrix.postTranslate((width - dw) / 2, (height - dh) / 2); + mScaleMatrix.postScale(scale, scale, getWidth() / 2, + getHeight() / 2); + setImageMatrix(mScaleMatrix); + isFirst = false; + } + + } + + public Bitmap cropBitmap() { + Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), + Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + draw(canvas); + return Bitmap.createBitmap(bitmap, mOffset, + mVOffset, getWidth() - 2 * mOffset, + getWidth() - 2 * mOffset); + } + + private void checkBorder() { + RectF rect = getMatrixRectF(); + float deltaX = 0; + float deltaY = 0; + + int width = getWidth(); + int height = getHeight(); + + if (rect.width() + 0.01 >= width - 2 * mOffset) { + if (rect.left > mOffset) { + deltaX = -rect.left + mOffset; + } + if (rect.right < width - mOffset) { + deltaX = width - mOffset - rect.right; + } + } + if (rect.height() + 0.01 >= height - 2 * mVOffset) { + if (rect.top > mVOffset) { + deltaY = -rect.top + mVOffset; + } + if (rect.bottom < height - mVOffset) { + deltaY = height - mVOffset - rect.bottom; + } + } + mScaleMatrix.postTranslate(deltaX, deltaY); + + } + + private boolean isCanDrag(float dx, float dy) { + return Math.sqrt((dx * dx) + (dy * dy)) >= 0; + } + + public void setHOffset(int hOffset) { + this.mOffset = hOffset; + } + + public void setVOffset(int vOffset) { + this.mVOffset = vOffset; + } + + public void setCropWidth(int mCropWidth) { + this.mCropWidth = mCropWidth; + } + + public void setCropHeight(int mCropHeight) { + this.mCropHeight = mCropHeight; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/notice/NoticeBean.java b/app/src/main/java/net/oschina/app/improve/notice/NoticeBean.java new file mode 100644 index 0000000000000000000000000000000000000000..8d390f0063840d631c3c269b86a847514ee6106e --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/notice/NoticeBean.java @@ -0,0 +1,105 @@ +package net.oschina.app.improve.notice; + +import android.content.Context; + +import net.oschina.common.helper.SharedPreferencesHelper; + +import java.io.Serializable; + +/** + * Created by JuQiu + * on 16/8/19. + * Note: like count always zero + */ +public class NoticeBean implements Serializable { + private int mention; + private int letter; + private int review; + private int fans; + private int like = 0; + + public int getMention() { + return mention; + } + + void setMention(int mention) { + this.mention = mention; + } + + public int getLetter() { + return letter; + } + + void setLetter(int letter) { + this.letter = letter; + } + + public int getReview() { + return review; + } + + void setReview(int review) { + this.review = review; + } + + public int getFans() { + return fans; + } + + void setFans(int fans) { + this.fans = fans; + } + + public int getLike() { + return like; + } + + void setLike(int like) { + this.like = 0; + } + + public int getAllCount() { + return mention + letter + review + fans; + } + + @Override + public String toString() { + return "NoticeBean{" + + "mention=" + mention + + ", letter=" + letter + + ", review=" + review + + ", fans=" + fans + + ", like=" + like + + '}'; + } + + void clear() { + this.mention = 0; + this.letter = 0; + this.review = 0; + this.fans = 0; + this.like = 0; + } + + NoticeBean add(NoticeBean bean) { + this.mention += bean.mention; + this.letter += bean.letter; + this.review += bean.review; + this.fans += bean.fans; + // 暂不累加点赞数据 + //this.like += bean.like; + return this; + } + + NoticeBean save(Context context) { + SharedPreferencesHelper.save(context, this); + return this; + } + + static NoticeBean getInstance(Context context) { + NoticeBean bean = SharedPreferencesHelper.load(context, NoticeBean.class); + if (bean == null) + bean = new NoticeBean(); + return bean; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/notice/NoticeManager.java b/app/src/main/java/net/oschina/app/improve/notice/NoticeManager.java new file mode 100644 index 0000000000000000000000000000000000000000..80a0d0f31fb9866f7a191d4f0bfb6cfe89e94ed5 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/notice/NoticeManager.java @@ -0,0 +1,128 @@ +package net.oschina.app.improve.notice; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; + +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.common.BuildConfig; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by JuQiu + * on 16/8/18. + */ +public final class NoticeManager { + public static final int FLAG_CLEAR_MENTION = 0x1; + public static final int FLAG_CLEAR_LETTER = 0x2; + public static final int FLAG_CLEAR_REVIEW = 0x3; + public static final int FLAG_CLEAR_FANS = 0x4; + public static final int FLAG_CLEAR_LIKE = 0x5; + public static final int FLAG_CLEAR_ALL = 0x6; + + private static NoticeManager INSTANCE; + + static { + INSTANCE = new NoticeManager(); + } + + private NoticeManager() { + + } + + private final List mNotifies = new ArrayList<>(); + private NoticeBean mNotice; + + public static NoticeBean getNotice() { + final NoticeBean bean = INSTANCE.mNotice; + if (bean == null) { + return new NoticeBean(); + } else { + return bean; + } + } + + public static void bindNotify(NoticeNotify noticeNotify) { + INSTANCE.mNotifies.add(noticeNotify); + INSTANCE.check(noticeNotify); + } + + public static void unBindNotify(NoticeNotify noticeNotify) { + INSTANCE.mNotifies.remove(noticeNotify); + } + + private void check(NoticeNotify noticeNotify) { + if (mNotice != null) + noticeNotify.onNoticeArrived(mNotice); + } + + public static void init(Context context) { + // 未登陆时不启动服务 + if (!AccountHelper.isLogin()) { + return; + } + // 启动服务 + NoticeServer.startAction(context); + // 注册广播 + IntentFilter filter = new IntentFilter(NoticeServer.FLAG_BROADCAST_REFRESH); + context.registerReceiver(INSTANCE.mReceiver, filter); + } + + public static void stopListen(Context context) { + try { + context.unregisterReceiver(INSTANCE.mReceiver); + } catch (IllegalArgumentException e) { + if (BuildConfig.DEBUG) + e.printStackTrace(); + } + } + + public static void exitServer(Context context) { + NoticeServer.startActionExit(context); + } + + /** + * 已读清理Context + * + * @param context Context + * @param type {@link #FLAG_CLEAR_MENTION}, {@link #FLAG_CLEAR_LETTER}, + * {@link #FLAG_CLEAR_REVIEW},{@link #FLAG_CLEAR_FANS}, + * {@link #FLAG_CLEAR_LIKE} + */ + public static void clear(Context context, int type) { + NoticeServer.startActionClear(context, type); + } + + public interface NoticeNotify { + void onNoticeArrived(NoticeBean bean); + } + + private BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction() != null && + NoticeServer.FLAG_BROADCAST_REFRESH.equals(intent.getAction())) { + Serializable serializable = intent.getSerializableExtra(NoticeServer.EXTRA_BEAN); + if (serializable != null) { + try { + onNoticeChanged((NoticeBean) serializable); + } catch (Exception e) { + e.fillInStackTrace(); + } + } + } + } + }; + + private void onNoticeChanged(NoticeBean bean) { + mNotice = bean; + // Notify all + for (NoticeNotify notify : mNotifies) { + notify.onNoticeArrived(mNotice); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/notice/NoticeServer.java b/app/src/main/java/net/oschina/app/improve/notice/NoticeServer.java new file mode 100644 index 0000000000000000000000000000000000000000..92f77a8eb92a3e163e5d901db61c3cfeb6f7750b --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/notice/NoticeServer.java @@ -0,0 +1,336 @@ +package net.oschina.app.improve.notice; + +import android.annotation.SuppressLint; +import android.app.AlarmManager; +import android.app.Notification; +import android.app.PendingIntent; +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.os.IBinder; +import android.os.SystemClock; +import android.support.v4.app.NotificationCompat; +import android.support.v4.app.NotificationManagerCompat; +import android.text.TextUtils; +import android.view.animation.AccelerateInterpolator; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.R; +import net.oschina.app.api.ApiHttpClient; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.main.MainActivity; +import net.oschina.app.util.TLog; + +import java.lang.reflect.Type; + +import cz.msebera.android.httpclient.Header; + +/** + * Created by JuQiu + * on 16/8/18. + */ +public class NoticeServer extends Service { + private static final String TAG = NoticeServer.class.getName(); + + static final String FLAG_BROADCAST_REFRESH = TAG + "_BROADCAST_REFRESH"; + + private static final String FLAG_ACTION_FIRST = TAG + "_FIRST"; + private static final String FLAG_ACTION_REFRESH = TAG + "_REFRESH"; + private static final String FLAG_ACTION_CLEAR = TAG + "_CLEAR"; + private static final String FLAG_ACTION_EXIT = TAG + "_EXIT"; + + private static final String EXTRA_TYPE = "type"; + static final String EXTRA_BEAN = "bean"; + + private AlarmManager mAlarmMgr; + + static void startAction(Context context) { + Intent intent = new Intent(context, NoticeServer.class); + intent.setAction(FLAG_ACTION_FIRST); + context.startService(intent); + log("startAction"); + } + + static void startActionClear(Context context, int type) { + Intent intent = new Intent(context, NoticeServer.class); + intent.setAction(FLAG_ACTION_CLEAR); + intent.putExtra(EXTRA_TYPE, type); + context.startService(intent); + log("startActionClear"); + } + + static void startActionExit(Context context) { + Intent intent = new Intent(context, NoticeServer.class); + intent.setAction(FLAG_ACTION_EXIT); + context.startService(intent); + log("startActionExit"); + } + + public NoticeServer() { + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + if (intent == null) { + log("onStartCommand: intent is null."); + return super.onStartCommand(null, flags, startId); + } + String action = intent.getAction(); + log("onStartCommand:" + action); + if (action != null) { + handleAction(action, intent); + } + return super.onStartCommand(intent, flags, startId); + } + + @Override + public void onCreate() { + super.onCreate(); + log("onCreate"); + // First init the Client + ApiHttpClient.init(getApplication()); + mAlarmMgr = (AlarmManager) getSystemService(ALARM_SERVICE); + } + + @Override + public void onDestroy() { + log("onDestroy"); + super.onDestroy(); + } + + private final static int ALARM_INTERVAL_MIN = 0; + private final static int ALARM_INTERVAL_MAX = 15; + + private final static int ALARM_INTERVAL_MIN_SECOND = 15; + private final static int ALARM_INTERVAL_MAX_SECOND = 15 * 60; + // The count 0~15, 20s->15*60s + private static int mAlarmCount = ALARM_INTERVAL_MIN; + + private void registerFirstAlarm() { + long interval = getAlarmInterval(0); + registerAlarmByInterval(interval); + } + + private void registerCurrentAlarm(boolean increase) { + if (increase) { + mAlarmCount++; + if (mAlarmCount > ALARM_INTERVAL_MAX) + mAlarmCount = ALARM_INTERVAL_MAX; + } else { + mAlarmCount--; + if (mAlarmCount < ALARM_INTERVAL_MIN) + mAlarmCount = ALARM_INTERVAL_MIN; + } + log("registerCurrentAlarm:increase:" + increase); + long interval = getAlarmInterval(mAlarmCount); + registerAlarmByInterval(interval); + } + + private void registerAlarmByInterval(long interval) { + cancelRequestAlarm(); + mAlarmMgr.setRepeating(AlarmManager.ELAPSED_REALTIME, + SystemClock.elapsedRealtime() + interval, interval, getOperationIntent()); + log("registerAlarmByInterval interval:" + interval); + } + + + private long getAlarmInterval(int count) { + mAlarmCount = count; + + float progress = mAlarmCount / (float) ALARM_INTERVAL_MAX; + progress = new AccelerateInterpolator(2.2f).getInterpolation(progress); + + int millisecond = (int) (1000 * (ALARM_INTERVAL_MIN_SECOND + ((ALARM_INTERVAL_MAX_SECOND - ALARM_INTERVAL_MIN_SECOND) * progress))); + log("getAlarmInterval:mAlarmCount:" + mAlarmCount + " progress:" + progress + " millisecond:" + millisecond); + return millisecond; + } + + private void cancelRequestAlarm() { + mAlarmMgr.cancel(getOperationIntent()); + } + + private PendingIntent getOperationIntent() { + Intent intent = new Intent(this, NoticeServer.class); + intent.setAction(FLAG_ACTION_REFRESH); + return PendingIntent.getService(this, 0, intent, + PendingIntent.FLAG_UPDATE_CURRENT); + } + + private void handleAction(String action, Intent intent) { + if (FLAG_ACTION_REFRESH.equals(action)) { + refreshNotice(); + } else if (FLAG_ACTION_CLEAR.equals(action)) { + clearNotice(intent.getIntExtra(EXTRA_TYPE, 0)); + } else if (FLAG_ACTION_EXIT.equals(action)) { + cancelRequestAlarm(); + stopSelf(); + } else if (FLAG_ACTION_FIRST.equals(action)) { + registerFirstAlarm(); + // First notify + sendBroadcastToManager(NoticeBean.getInstance(this)); + } + } + + private boolean mRunning; + + private synchronized void refreshNotice() { + log("refreshNotice: mRunning:" + mRunning); + if (mRunning) + return; + + mRunning = true; + OSChinaApi.getNotice(new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + log("onFailure:" + statusCode + " " + responseString); + doNetFinish(null); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + log("onSuccess:" + statusCode + " " + responseString); + if (!TextUtils.isEmpty(responseString)) { + try { + Type type = new TypeToken>() { + }.getType(); + ResultBean bean = new Gson().fromJson(responseString, type); + doNetFinish(bean); + } catch (Exception e) { + onFailure(statusCode, headers, responseString, e.fillInStackTrace()); + } + } else { + onFailure(statusCode, headers, responseString, null); + } + } + + @Override + public void onFinish() { + super.onFinish(); + mRunning = false; + } + }); + } + + private void doNetFinish(ResultBean bean) { + log("doNetFinish:" + (bean == null ? "null" : bean.toString())); + if (bean != null && bean.isSuccess() + && bean.getResult() != null + && bean.getResult().getAllCount() > 0) { + NoticeBean request = bean.getResult(); + NoticeBean notice = NoticeBean.getInstance(this) + .add(request) + .save(this); + // To register alarm + registerCurrentAlarm(false); + // Send to manager + sendBroadcastToManager(notice); + // Send to notification + sendNotification(notice); + } else { + // To register alarm + registerCurrentAlarm(true); + } + } + + private void clearNotice(int type) { + log("clearNotice:" + type); + NoticeBean notice = NoticeBean.getInstance(this); + switch (type) { + case NoticeManager.FLAG_CLEAR_MENTION: + notice.setMention(0); + break; + case NoticeManager.FLAG_CLEAR_LETTER: + notice.setLetter(0); + break; + case NoticeManager.FLAG_CLEAR_REVIEW: + notice.setReview(0); + break; + case NoticeManager.FLAG_CLEAR_FANS: + notice.setFans(0); + break; + case NoticeManager.FLAG_CLEAR_LIKE: + notice.setLike(0); + break; + case NoticeManager.FLAG_CLEAR_ALL: + notice.clear(); + break; + } + notice.save(this); + sendBroadcastToManager(notice); + sendNotification(notice); + } + + private void sendBroadcastToManager(NoticeBean bean) { + log("sendBroadcastToManager:" + bean.toString()); + Intent intent = new Intent(FLAG_BROADCAST_REFRESH); + intent.putExtra(EXTRA_BEAN, bean); + sendBroadcast(intent); + } + + private final static int NOTIFY_ID = 0x11111111; + + @SuppressLint("StringFormatMatches") + private void sendNotification(NoticeBean bean) { + if (bean == null || bean.getAllCount() == 0) { + clearNotification(); + return; + } + + log("sendNotification:" + bean.toString()); + + StringBuilder sb = new StringBuilder(); + if (bean.getMention() > 0) { + sb.append(getString(R.string.mention_count, bean.getMention())).append(" "); + } + if (bean.getLetter() > 0) { + sb.append(getString(R.string.letter_count, bean.getLetter())).append(" "); + } + if (bean.getReview() > 0) { + sb.append(getString(R.string.review_count, bean.getReview())) + .append(" "); + } + if (bean.getFans() > 0) { + sb.append(getString(R.string.fans_count, bean.getFans())); + } + if (bean.getLike() > 0) { + sb.append(getString(R.string.like_count, bean.getLike())); + } + String content = sb.toString(); + + Intent intent = new Intent(this, MainActivity.class); + intent.setAction(MainActivity.ACTION_NOTICE); + PendingIntent contentIntent = PendingIntent.getActivity(this, NOTIFY_ID, intent, + PendingIntent.FLAG_CANCEL_CURRENT); + + NotificationCompat.Builder builder = new NotificationCompat.Builder( + this) + .setTicker(content) + .setContentTitle(getString(R.string.you_have_unread_messages, bean.getAllCount())) + .setContentText(content) + .setAutoCancel(true) + .setOngoing(false) + .setContentIntent(contentIntent) + .setSmallIcon(R.mipmap.ic_notification); + + Notification notification = builder.build(); + NotificationManagerCompat.from(this).notify(NOTIFY_ID, notification); + } + + private void clearNotification() { + log("clearNotification"); + NotificationManagerCompat.from(this).cancel(NOTIFY_ID); + } + + static void log(String str) { + TLog.d(TAG, str); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/pay/bean/Order.java b/app/src/main/java/net/oschina/app/improve/pay/bean/Order.java new file mode 100644 index 0000000000000000000000000000000000000000..1e4762e700f10edaec026215e4d5eddedfa3bc69 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/pay/bean/Order.java @@ -0,0 +1,77 @@ +package net.oschina.app.improve.pay.bean; + +import java.io.Serializable; + +/** + * Created by thanatos on 16/10/11. + */ + +public class Order implements Serializable { + + public static final String TYPE_ALIPAY = "alipay"; // 支付宝支付 + public static final String TYPE_WEPAY = "wepay"; // 微信支付 + + private long objType; + private long objId; + private float money; + private String attach; + private String payInfo; + private String message; + private String pubDate; + + public long getObjType() { + return objType; + } + + public void setObjType(long objType) { + this.objType = objType; + } + + public long getObjId() { + return objId; + } + + public void setObjId(long objId) { + this.objId = objId; + } + + public float getMoney() { + return money; + } + + public void setMoney(float money) { + this.money = money; + } + + public String getAttach() { + return attach; + } + + public void setAttach(String attach) { + this.attach = attach; + } + + public String getPayInfo() { + return payInfo; + } + + public void setPayInfo(String payInfo) { + this.payInfo = payInfo; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getPubDate() { + return pubDate; + } + + public void setPubDate(String pubDate) { + this.pubDate = pubDate; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/pay/bean/ResultBean.java b/app/src/main/java/net/oschina/app/improve/pay/bean/ResultBean.java new file mode 100644 index 0000000000000000000000000000000000000000..45c451dea31cb2e70098674abc28f9360a63b275 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/pay/bean/ResultBean.java @@ -0,0 +1,47 @@ +package net.oschina.app.improve.pay.bean; + +import java.io.Serializable; + +/** + * Created by thanatos on 16/10/11. + */ + +public class ResultBean implements Serializable { + + private int code; + private String message; + private String time; + private T result; + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getTime() { + return time; + } + + public void setTime(String time) { + this.time = time; + } + + public T getResult() { + return result; + } + + public void setResult(T result) { + this.result = result; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/pay/dialog/RewardDialog.java b/app/src/main/java/net/oschina/app/improve/pay/dialog/RewardDialog.java new file mode 100644 index 0000000000000000000000000000000000000000..1d7b12685de25f67753317db8f17d362fa39e2b0 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/pay/dialog/RewardDialog.java @@ -0,0 +1,174 @@ +package net.oschina.app.improve.pay.dialog; + +import android.app.Dialog; +import android.content.Context; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.Button; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.bumptech.glide.Glide; + +import net.oschina.app.R; +import net.oschina.app.util.SimpleTextWatcher; + +import butterknife.Bind; +import butterknife.ButterKnife; +import butterknife.OnClick; +import de.hdodenhof.circleimageview.CircleImageView; + +/** + * 打赏 dialog + * Created by thanatos on 16/10/12. + */ + +public class RewardDialog extends Dialog implements View.OnClickListener { + + @Bind(R.id.img_portrait) + CircleImageView mPortrait; + @Bind(R.id.tv_nick) + TextView mNick; + @Bind(R.id.tv_info) + TextView mInfo; + @Bind(R.id.et_input) + EditText mInput; + @Bind(R.id.tv_pay_choice) + TextView mPayChoice; + @Bind(R.id.btn_reward) + Button mBtnReward; + @Bind(R.id.layout_casts) + LinearLayout mLayoutCasts; + + private String portrait; + private String nick; + private OnClickRewardCallback callback; + + public RewardDialog(Context context) { + super(context); + } + + public interface OnClickRewardCallback { + void reward(float cast); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + requestWindowFeature(Window.FEATURE_NO_TITLE); + super.onCreate(savedInstanceState); + setContentView(R.layout.view_dialog_reward); + ButterKnife.bind(this); + + WindowManager.LayoutParams params = getWindow().getAttributes(); + params.width = getWindow().getWindowManager().getDefaultDisplay().getWidth(); + getWindow().setAttributes(params); + + // TODO 支持多平台支付,后期添加微信支付 + mInfo.setText("使用支付宝支付"); + mPayChoice.setVisibility(View.GONE); + + Glide.with(getContext()) + .load(portrait) + .asBitmap() + .placeholder(R.mipmap.widget_dface) + .error(R.mipmap.widget_dface) + .into(mPortrait); + mNick.setText(nick); + + mBtnReward.setEnabled(false); + mInput.addTextChangedListener(new SimpleTextWatcher() { + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + super.onTextChanged(s, start, before, count); + if (TextUtils.isEmpty(s)) { + mBtnReward.setEnabled(false); + return; + } + String mCastStr = s.toString(); + float cast = 0; + try { + cast = Float.valueOf(mCastStr); + } catch (Exception e) { + cast = 0; + mInput.setText(null); + } + if (cast <= 0) mBtnReward.setEnabled(false); + else mBtnReward.setEnabled(true); + } + }); + + int count = mLayoutCasts.getChildCount(); + for (int i = 0; i < count; i++) { + View view = mLayoutCasts.getChildAt(i); + view.setOnClickListener(this); + } + selectAt(null, count - 1); + } + + private void selectAt(View v, int index) { + int count = mLayoutCasts.getChildCount(); + for (int i = 0; i < count; i++) { + mLayoutCasts.getChildAt(i).setSelected(false); + } + if (v == null) { + mLayoutCasts.getChildAt(index).setSelected(true); + } else { + v.setSelected(true); + } + } + + public void setPortrait(String portrait) { + this.portrait = portrait; + } + + public void setNick(String nick) { + this.nick = nick; + } + + @Override + public void onClick(View v) { + Object o = v.getTag(); + if (o == null) return; + selectAt(v, 0); + String mCastStr = o.toString(); + int cast; + try { + cast = Integer.valueOf(mCastStr); + } catch (Exception e) { + cast = -1; + } + // 其他金额 + if (cast == -1) { + mInput.setText(null); + return; + } + mInput.setText(mCastStr); + mInput.setSelection(mCastStr.length()); + } + + public void setOnClickRewardListener(OnClickRewardCallback callback) { + this.callback = callback; + } + + @OnClick(R.id.btn_reward) + void onClickReward() { + String mCastStr = mInput.getText().toString(); + float cast = Float.valueOf(mCastStr); + if (cast < 0.01) { + Toast.makeText(getContext(), "最低悬赏0.01元", Toast.LENGTH_SHORT).show(); + return; + } + if (cast > 9999999.99) { + Toast.makeText(getContext(), "最高悬赏9999999.99", Toast.LENGTH_SHORT).show(); + return; + } + if (callback == null) return; + callback.reward(cast); + } + +} diff --git a/app/src/main/java/net/oschina/app/improve/pay/platform/Alipay.java b/app/src/main/java/net/oschina/app/improve/pay/platform/Alipay.java new file mode 100644 index 0000000000000000000000000000000000000000..84ae71f01ab021995c6ea984762170b44b9ce08d --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/pay/platform/Alipay.java @@ -0,0 +1,101 @@ +package net.oschina.app.improve.pay.platform; + +import android.app.Activity; +import android.os.Handler; +import android.os.Message; +import android.text.TextUtils; + +import java.util.Map; + +/** + * 支付宝支付 + * Created by thanatos on 2016/10/11. + */ + +public class Alipay { + + public static final int PAY_RESULT_CODE_SUCCESS = 9000; + public static final int PAY_RESULT_CODE_DEALING = 8000; + public static final int PAY_RESULT_CODE_FAILURE = 4000; + public static final int PAY_RESULT_CODE_REPEAT_REQUEST = 5000; + public static final int PAY_RESULT_CODE_CANCEL = 6001; + public static final int PAY_RESULT_CODE_INTERNET_ERROR = 6002; + public static final int PAY_RESULT_CODE_UNKNOWN = 6004; + + private Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + Map result = (Map) msg.obj; + if (result == null) return; + String status = result.get("resultStatus"); + if (TextUtils.isEmpty(status)) return; + int code = Integer.valueOf(status); + switch (code) { + case PAY_RESULT_CODE_SUCCESS: + onSuccess(); + break; + case PAY_RESULT_CODE_DEALING: + onDealing(); + break; + case PAY_RESULT_CODE_FAILURE: + onFailure(); + break; + case PAY_RESULT_CODE_REPEAT_REQUEST: + onRepeatRequest(); + break; + case PAY_RESULT_CODE_CANCEL: + onCancel(); + break; + case PAY_RESULT_CODE_INTERNET_ERROR: + onInternetError(); + break; + case PAY_RESULT_CODE_UNKNOWN: + onUnknownError(); + break; + } + } + }; + + public void pay(final Activity activity, final String payinfo) { + new Thread(new Runnable() { + @Override + public void run() { +// PayTask alipay = new PayTask(activity); +// Map result = alipay.payV2(payinfo, true); +// +// Message msg = mHandler.obtainMessage(); +// msg.obj = result; +// mHandler.sendMessage(msg); + } + }).start(); + } + + public void onSuccess() { + // do when success + } + + public void onDealing() { + // pass + } + + public void onFailure() { + // pass + } + + public void onRepeatRequest() { + // repeat request result + } + + public void onCancel() { + // cancel pay + } + + public void onInternetError() { + // internet error + } + + public void onUnknownError() { + // other error unknown + } + +} diff --git a/app/src/main/java/net/oschina/app/improve/pay/platform/WXPay.java b/app/src/main/java/net/oschina/app/improve/pay/platform/WXPay.java new file mode 100644 index 0000000000000000000000000000000000000000..3da3ebf676bac8b505bf87d1df6e0344c2f6d3e5 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/pay/platform/WXPay.java @@ -0,0 +1,101 @@ +package net.oschina.app.improve.pay.platform; + +import android.app.Activity; +import android.support.v4.util.Pair; +import android.text.TextUtils; + +import com.tencent.mm.sdk.constants.ConstantsAPI; +import com.tencent.mm.sdk.modelbase.BaseReq; +import com.tencent.mm.sdk.modelbase.BaseResp; +import com.tencent.mm.sdk.modelpay.PayReq; +import com.tencent.mm.sdk.openapi.IWXAPI; +import com.tencent.mm.sdk.openapi.IWXAPIEventHandler; +import com.tencent.mm.sdk.openapi.WXAPIFactory; + +import net.oschina.app.util.TLog; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * Created by thanatos on 16/10/11. + */ + +public class WXPay implements IWXAPIEventHandler { + + public static final int PAY_RESULT_CODE_SUCCESS = 0; + public static final int PAY_RESULT_CODE_ERROR = -1; + public static final int PAY_RESULT_CODE_CANCEL = -2; + + private static String APP_ID = ""; + private IWXAPI iwxapi; + + public WXPay(Activity context) { + iwxapi = WXAPIFactory.createWXAPI(context, APP_ID, true); + iwxapi.handleIntent(context.getIntent(), this); + } + + private void pay(Map map) { + PayReq request = new PayReq(); + request.appId = APP_ID; + request.partnerId = map.get("partnerId"); + request.prepayId = map.get("prepayId"); + request.packageValue = map.get("packageValue"); + request.nonceStr = map.get("nonceStr"); + request.timeStamp = map.get("timeStamp"); + request.sign = map.get("sign"); + iwxapi.sendReq(request); + } + + @Override + public void onReq(BaseReq baseReq) { + + } + + @Override + public void onResp(BaseResp resp) { + if (resp.getType() != ConstantsAPI.COMMAND_PAY_BY_WX) return; + TLog.d("oschina", "微信支付成功"); + switch (resp.errCode) { + case PAY_RESULT_CODE_SUCCESS: + break; + case PAY_RESULT_CODE_ERROR: + break; + case PAY_RESULT_CODE_CANCEL: + break; + } + } + + public static List> decode(String info) { + List> list = new ArrayList<>(); + if (TextUtils.isEmpty(info)) return list; + String[] kv = info.split("&"); + String[] k; + for (String v : kv) { + k = v.split("="); + if (k.length != 2) continue; + try { + list.add(Pair.create(k[0], URLEncoder.encode(k[1], "UTF-8"))); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + TLog.d("oschina", "encode url parameter error"); + } + } + return list; + } + + public void onSuccess() { + // when success + } + + public void onError() { + // error + } + + public void onCancel() { + // user cancel pay the order + } +} diff --git a/app/src/main/java/net/oschina/app/improve/pay/util/RewardUtil.java b/app/src/main/java/net/oschina/app/improve/pay/util/RewardUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..ecbe3d93d86704afda636800a23acf9427601d8e --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/pay/util/RewardUtil.java @@ -0,0 +1,98 @@ +package net.oschina.app.improve.pay.util; + +import java.security.SecureRandom; +import java.util.Map; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.DESKeySpec; + +/** + * Created by thanatos on 16/10/12. + */ + +public class RewardUtil { + + public static final String REWARD_SECURITY_KEY = "19328_etanod_cso_4_yek_sed_a_si_sihT"; + + /** + * 二行制转字符串 + * + * @param b + * @return + */ + private static String byte2hex(byte[] b) { + StringBuilder hs = new StringBuilder(); + String stmp; + for (int n = 0; b != null && n < b.length; n++) { + stmp = Integer.toHexString(b[n] & 0XFF); + if (stmp.length() == 1) + hs.append('0'); + hs.append(stmp); + } + return hs.toString().toUpperCase(); + } + + public static String encrypt(String data, String key) { + return byte2hex(encrypt(data.getBytes(), key.getBytes())); + } + + /** + * 加密函数 + * + * @param data 加密数据 + * @param key 密钥 + * @return 返回加密后的数据 + */ + public static byte[] encrypt(byte[] data, byte[] key) { + try { + SecureRandom sr = new SecureRandom(); + DESKeySpec dks = new DESKeySpec(key); + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); + SecretKey secretKey = keyFactory.generateSecret(dks); + Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); + cipher.init(Cipher.ENCRYPT_MODE, secretKey, sr); + return cipher.doFinal(data); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public static String decrypt(String data, String key) { + return decrypt(data.getBytes(), key.getBytes()); + } + + /** + * 解密函数 + * + * @param data 解密数据 + * @param key 密钥 + * @return 返回解密后的数据 + */ + public static String decrypt(byte[] data, byte[] key) { + try { + SecureRandom sr = new SecureRandom(); + DESKeySpec dks = new DESKeySpec(key); + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); + SecretKey secretKey = keyFactory.generateSecret(dks); + Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); + cipher.init(Cipher.DECRYPT_MODE, secretKey, sr); + return new String(cipher.doFinal(data)); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public static String sign(Map pairs) { + String sign = ""; + for (Map.Entry pair : pairs.entrySet()) { + //if (TextUtils.isEmpty(pair.getValue())) continue; + sign += "&" + pair.getKey() + "=" + pair.getValue(); + } + sign = sign.substring(1, sign.length() - 1); + return encrypt(sign, REWARD_SECURITY_KEY); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/search/activities/SearchActivity.java b/app/src/main/java/net/oschina/app/improve/search/activities/SearchActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..a6e70367fddf49a488a74d4a8a7edd583c1334f2 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/search/activities/SearchActivity.java @@ -0,0 +1,253 @@ +package net.oschina.app.improve.search.activities; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.design.widget.TabLayout; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentStatePagerAdapter; +import android.support.v4.util.Pair; +import android.support.v4.view.ViewPager; +import android.support.v7.widget.SearchView; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.LinearLayout; + +import net.oschina.app.R; +import net.oschina.app.improve.base.activities.BaseActivity; +import net.oschina.app.improve.bean.News; +import net.oschina.app.improve.search.fragments.SearchArticleFragment; +import net.oschina.app.improve.search.fragments.SearchUserFragment; +import net.oschina.app.util.TDevice; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import butterknife.Bind; +import butterknife.OnClick; + +/** + * 搜索界面 + * Created by thanatos on 16/9/7. + */ + +public class SearchActivity extends BaseActivity implements ViewPager.OnPageChangeListener { + + @Bind(R.id.view_root) + LinearLayout mViewRoot; + @Bind(R.id.layout_tab) + TabLayout mLayoutTab; + @Bind(R.id.view_pager) + ViewPager mViewPager; + @Bind(R.id.view_searcher) + SearchView mViewSearch; + @Bind(R.id.search_mag_icon) + ImageView mSearchIcon; + @Bind(R.id.search_edit_frame) + LinearLayout mLayoutEditFrame; + @Bind(R.id.search_src_text) + EditText mViewSearchEditor; + + private List> mPagerItems; + + private static boolean isMiUi = false; + + public static void show(Context context) { + Intent intent = new Intent(context, SearchActivity.class); + context.startActivity(intent); + } + + public void setStatusBarDarkMode(boolean darkMode) { + if (isMiUi) { + Class clazz = getWindow().getClass(); + try { + int darkModeFlag; + Class layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams"); + Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE"); + darkModeFlag = field.getInt(layoutParams); + Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class); + extraFlagField.invoke(getWindow(), darkMode ? darkModeFlag : 0, darkModeFlag); + } catch (Exception e) { + // 这个API, MDZZ + e.printStackTrace(); + } + } + } + + /** + * 静态域,获取系统版本是否基于MIUI + */ + static { + try { + Class sysClass = Class.forName("android.os.SystemProperties"); + Method getStringMethod = sysClass.getDeclaredMethod("get", String.class); + String version = (String) getStringMethod.invoke(sysClass, "ro.miui.ui.version.name"); + isMiUi = version.compareTo("V6") >= 0; + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + // pass + } + + @Override + public void onPageSelected(int position) { + String content = mSearchText; + if (TextUtils.isEmpty(content)) return; + doSearch(content, false); + } + + @Override + public void onPageScrollStateChanged(int state) { + // pass + } + + public interface SearchAction { + void search(String content); + } + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + protected int getContentView() { + return R.layout.activity_v2_search; + } + + @Override + protected void initWindow() { + mPagerItems = new ArrayList<>(); + + mPagerItems.add(new Pair<>("博客", SearchArticleFragment.instantiate(this, News.TYPE_BLOG))); + mPagerItems.add(new Pair<>("软件", SearchArticleFragment.instantiate(this, News.TYPE_SOFTWARE))); + mPagerItems.add(new Pair<>("资讯", SearchArticleFragment.instantiate(this, News.TYPE_NEWS))); + mPagerItems.add(new Pair<>("问答", SearchArticleFragment.instantiate(this, News.TYPE_QUESTION))); + mPagerItems.add(new Pair<>("找人", SearchUserFragment.instantiate(this))); + } + + @Override + protected void onStop() { + super.onStop(); + mViewSearch.clearFocus(); + } + + @Override + protected void initWidget() { + super.initWidget(); + setStatusBarDarkMode(true); + mViewSearchEditor.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); + mViewSearch.setOnCloseListener(new SearchView.OnCloseListener() { + @Override + public boolean onClose() { + // 阻止点击关闭按钮 collapse icon + return true; + } + }); + mViewSearch.setOnQueryTextListener(new SearchView.OnQueryTextListener() { + @Override + public boolean onQueryTextSubmit(String query) { + mViewSearch.clearFocus(); + return doSearch(query, false); + } + + @Override + public boolean onQueryTextChange(String newText) { + return doSearch(newText, true); + } + }); + + mViewPager.setAdapter(new FragmentStatePagerAdapter(getSupportFragmentManager()) { + @Override + public Fragment getItem(int position) { + return mPagerItems.get(position).second; + } + + @Override + public int getCount() { + return mPagerItems.size(); + } + + @Override + public CharSequence getPageTitle(int position) { + return mPagerItems.get(position).first; + } + }); + mViewPager.addOnPageChangeListener(this); + mViewPager.setOffscreenPageLimit(0); + mLayoutTab.setupWithViewPager(mViewPager); + + LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) mSearchIcon.getLayoutParams(); + params.width = ViewGroup.LayoutParams.WRAP_CONTENT; + mSearchIcon.setLayoutParams(params); + + LinearLayout.LayoutParams params1 = (LinearLayout.LayoutParams) mLayoutEditFrame.getLayoutParams(); + params1.setMargins(0, 0, 0, 0); + mLayoutEditFrame.setLayoutParams(params1); + + mViewSearch.post(new Runnable() { + @Override + public void run() { +// TDevice.showSoftKeyboard(mViewSearch); + mViewSearch.setIconified(false); + } + }); + } + + + private String mSearchText; + private Runnable mSearchRunnable = new Runnable() { + @Override + public void run() { + if (TextUtils.isEmpty(mSearchText)) + return; + SearchAction f = (SearchAction) mPagerItems.get(mViewPager.getCurrentItem()).second; + f.search(mSearchText); + } + }; + + private boolean doSearch(String query, boolean fromTextChange) { + mSearchText = query.trim(); + // Always cancel all request + mViewPager.removeCallbacks(mSearchRunnable); + // Search is'nt empty + if (TextUtils.isEmpty(mSearchText)) { + mLayoutTab.setVisibility(View.GONE); + mViewPager.setVisibility(View.GONE); + return false; + } + + // Check network is wifi, by auto option + if (fromTextChange && !TDevice.isWifiOpen()) return false; + + mLayoutTab.setVisibility(View.VISIBLE); + mViewPager.setVisibility(View.VISIBLE); + + // In this we delay 1 seconds + mViewPager.postDelayed(mSearchRunnable, fromTextChange ? 1000 : 0); + return true; + } + + @OnClick(R.id.tv_cancel) + void onClickCancel() { + onBackPressed(); + } + + @Override + public void onBackPressed() { + super.onBackPressed(); + finish(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/search/adapters/SearchArticleAdapter.java b/app/src/main/java/net/oschina/app/improve/search/adapters/SearchArticleAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..827375b71c5b6385329b578cda9571d3bf0187a1 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/search/adapters/SearchArticleAdapter.java @@ -0,0 +1,57 @@ +package net.oschina.app.improve.search.adapters; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import net.oschina.app.R; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.bean.News; + +import butterknife.Bind; +import butterknife.ButterKnife; + +/** + * Created by thanatos on 16/10/24. + */ + +public class SearchArticleAdapter extends BaseRecyclerAdapter { + + public SearchArticleAdapter(Context context) { + this(context, ONLY_FOOTER); + } + + public SearchArticleAdapter(Context context, int mode) { + super(context, mode); + } + + @Override + protected RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type) { + return new ViewHolder(LayoutInflater.from(mContext) + .inflate(R.layout.list_item_search_article, parent, false)); + } + + @Override + protected void onBindDefaultViewHolder(RecyclerView.ViewHolder h, News item, int position) { + ViewHolder holder = (ViewHolder) h; + holder.mViewTitle.setText(item.getTitle()); + holder.mViewContent.setText(item.getBody()); + } + + public static class ViewHolder extends RecyclerView.ViewHolder { + + @Bind(R.id.tv_title) + TextView mViewTitle; + @Bind(R.id.tv_content) + TextView mViewContent; + + public ViewHolder(View view) { + super(view); + ButterKnife.bind(this, view); + } + } + +} diff --git a/app/src/main/java/net/oschina/app/improve/search/adapters/SearchUserAdapter.java b/app/src/main/java/net/oschina/app/improve/search/adapters/SearchUserAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..0467e7d86e8bd314dce3be4d1d33623c3f0928f1 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/search/adapters/SearchUserAdapter.java @@ -0,0 +1,76 @@ +package net.oschina.app.improve.search.adapters; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.bumptech.glide.Glide; + +import net.oschina.app.R; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.bean.User; + +import butterknife.Bind; +import butterknife.ButterKnife; +import de.hdodenhof.circleimageview.CircleImageView; + +/** + * Created by thanatos on 16/10/24. + */ + +public class SearchUserAdapter extends BaseRecyclerAdapter { + + public SearchUserAdapter(Context context) { + this(context, ONLY_FOOTER); + } + + public SearchUserAdapter(Context context, int mode) { + super(context, mode); + } + + @Override + protected RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type) { + return new ViewHolder(LayoutInflater.from(mContext) + .inflate(R.layout.list_item_search_person, parent, false)); + } + + @Override + protected void onBindDefaultViewHolder(RecyclerView.ViewHolder h, User item, int position) { + ViewHolder holder = (ViewHolder) h; + Glide.with(mContext) + .load(item.getPortrait()) + .asBitmap() + .placeholder(R.mipmap.widget_dface) + .error(R.mipmap.widget_dface) + .into(holder.mViewPortrait); + holder.mViewNick.setText(item.getName()); + holder.mViewPosition.setText(String.format("%s %s %s", + item.getMore().getCompany(), item.getMore().getPosition(), item.getMore().getCity()) + .replaceAll("null", "") + .trim() + ); + holder.mViewIntegral.setText(String.format("积分 %s | 关注 %s | 粉丝 %s", + item.getStatistics().getScore(), item.getStatistics().getFollow(), item.getStatistics().getFans())); + } + + public static class ViewHolder extends RecyclerView.ViewHolder { + + @Bind(R.id.iv_portrait) + CircleImageView mViewPortrait; + @Bind(R.id.tv_nick) + TextView mViewNick; + @Bind(R.id.tv_position) + TextView mViewPosition; + @Bind(R.id.tv_integral) + TextView mViewIntegral; + + public ViewHolder(View view) { + super(view); + ButterKnife.bind(this, view); + } + } + +} diff --git a/app/src/main/java/net/oschina/app/improve/search/fragments/SearchArticleFragment.java b/app/src/main/java/net/oschina/app/improve/search/fragments/SearchArticleFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..f30a351aac8ec648b8f3b1dd2f8692b156e4f600 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/search/fragments/SearchArticleFragment.java @@ -0,0 +1,118 @@ +package net.oschina.app.improve.search.fragments; + +import android.content.Context; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.text.TextUtils; +import android.view.View; + +import com.google.gson.reflect.TypeToken; + +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.base.fragments.BaseRecyclerViewFragment; +import net.oschina.app.improve.bean.News; +import net.oschina.app.improve.bean.base.PageBean; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.detail.activities.BlogDetailActivity; +import net.oschina.app.improve.detail.activities.NewsDetailActivity; +import net.oschina.app.improve.detail.activities.QuestionDetailActivity; +import net.oschina.app.improve.detail.activities.SoftwareDetailActivity; +import net.oschina.app.improve.search.activities.SearchActivity; +import net.oschina.app.improve.search.adapters.SearchArticleAdapter; +import net.oschina.app.util.UIHelper; + +import java.lang.reflect.Type; + +/** + * 博客、软件、资讯、问答的搜索界面 + * Created by thanatos on 16/10/18. + */ + +public class SearchArticleFragment extends BaseRecyclerViewFragment + implements SearchActivity.SearchAction { + + public static final String BUNDLE_KEY_CATALOG = "BUNDLE_KEY_CATALOG"; + + private int catalog = News.TYPE_NEWS; + private String content; + + public static Fragment instantiate(Context context, int catalog) { + Fragment fragment = new SearchArticleFragment(); + Bundle bundle = new Bundle(); + bundle.putInt(BUNDLE_KEY_CATALOG, catalog); + fragment.setArguments(bundle); + return fragment; + } + + @Override + protected void initBundle(Bundle bundle) { + super.initBundle(bundle); + catalog = bundle.getInt(BUNDLE_KEY_CATALOG, News.TYPE_NEWS); + } + + @Override + protected void initWidget(View root) { + super.initWidget(root); + mRefreshLayout.setRefreshing(false); + } + + @Override + protected BaseRecyclerAdapter getRecyclerAdapter() { + return new SearchArticleAdapter(getContext()); + } + + @Override + protected Type getType() { + return new TypeToken>>() { + }.getType(); + } + + @Override + protected void requestData() { + super.requestData(); + if (TextUtils.isEmpty(content)) { + mRefreshLayout.setRefreshing(false); + return; + } + String token = isRefreshing ? null : mBean.getNextPageToken(); + OSChinaApi.search(catalog, content, token, mHandler); + } + + @Override + public void onItemClick(int position, long itemId) { + super.onItemClick(position, itemId); + News item = mAdapter.getItem(position); + if (item == null) return; + switch (item.getType()) { + case News.TYPE_BLOG: + BlogDetailActivity.show(getContext(), item.getId()); + break; + case News.TYPE_QUESTION: + QuestionDetailActivity.show(getContext(), item.getId()); + break; + case News.TYPE_SOFTWARE: + SoftwareDetailActivity.show(getContext(), item.getId()); + break; + case News.TYPE_NEWS: + NewsDetailActivity.show(getContext(), item.getId()); + break; + default: + UIHelper.openInternalBrowser(getContext(), item.getHref()); + } + } + + @Override + public void search(String content) { + if (this.content != null && this.content.equals(content)) return; + this.content = content; + mAdapter.clear(); + mRefreshLayout.setRefreshing(true); + onRefreshing(); + } + + @Override + protected boolean isNeedEmptyView() { + return false; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/search/fragments/SearchUserFragment.java b/app/src/main/java/net/oschina/app/improve/search/fragments/SearchUserFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..6feae7607cfdc3576d1fbb57f437da4d6b1e339e --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/search/fragments/SearchUserFragment.java @@ -0,0 +1,77 @@ +package net.oschina.app.improve.search.fragments; + +import android.content.Context; +import android.support.v4.app.Fragment; +import android.text.TextUtils; + +import com.google.gson.reflect.TypeToken; + +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.base.fragments.BaseRecyclerViewFragment; +import net.oschina.app.improve.bean.News; +import net.oschina.app.improve.bean.User; +import net.oschina.app.improve.bean.base.PageBean; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.search.activities.SearchActivity; +import net.oschina.app.improve.search.adapters.SearchUserAdapter; +import net.oschina.app.improve.user.activities.OtherUserHomeActivity; + +import java.lang.reflect.Type; + +/** + * 搜索人界面 + * Created by thanatos + * on 16/10/24. + */ +public class SearchUserFragment extends BaseRecyclerViewFragment + implements SearchActivity.SearchAction { + + private String content; + + public static Fragment instantiate(Context context) { + return new SearchUserFragment(); + } + + @Override + protected BaseRecyclerAdapter getRecyclerAdapter() { + return new SearchUserAdapter(getContext()); + } + + @Override + protected Type getType() { + return new TypeToken>>() { + }.getType(); + } + + @Override + protected void requestData() { + super.requestData(); + if (TextUtils.isEmpty(content)) { + mRefreshLayout.setRefreshing(false); + return; + } + String token = isRefreshing ? null : mBean.getNextPageToken(); + OSChinaApi.search(News.TYPE_FIND_PERSON, content, token, mHandler); + } + + @Override + public void onItemClick(int position, long itemId) { + super.onItemClick(position, itemId); + OtherUserHomeActivity.show(getContext(), mAdapter.getItem(position).getId()); + } + + @Override + public void search(String content) { + if (this.content != null && this.content.equals(content)) return; + this.content = content; + mAdapter.clear(); + mRefreshLayout.setRefreshing(true); + onRefreshing(); + } + + @Override + protected boolean isNeedEmptyView() { + return false; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/tweet/activities/SoftwareTweetActivity.java b/app/src/main/java/net/oschina/app/improve/tweet/activities/SoftwareTweetActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..ddaaec6226a50d6f414728c7f6ef219b856b8fb6 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/tweet/activities/SoftwareTweetActivity.java @@ -0,0 +1,291 @@ +package net.oschina.app.improve.tweet.activities; + +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.support.design.widget.CoordinatorLayout; +import android.text.TextUtils; +import android.view.KeyEvent; +import android.view.View; +import android.widget.Toast; + +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.AppContext; +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.account.activity.LoginActivity; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.base.activities.BaseRecyclerViewActivity; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.bean.Tweet; +import net.oschina.app.improve.bean.base.PageBean; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.behavior.CommentBar; +import net.oschina.app.improve.tweet.adapter.SoftwareTweetAdapter; +import net.oschina.app.improve.utils.DialogHelper; +import net.oschina.app.ui.SelectFriendsActivity; +import net.oschina.app.util.TDevice; +import net.oschina.app.util.UIHelper; + +import java.lang.reflect.Type; + +import cz.msebera.android.httpclient.Header; + +import static net.oschina.app.improve.base.adapter.BaseRecyclerAdapter.ONLY_FOOTER; + +/** + * Created by fei on 2016/7/20. + * desc: + */ + +public class SoftwareTweetActivity extends BaseRecyclerViewActivity { + public static final String BUNDLE_KEY_NAME = "bundle_key_name"; + public static final String BUNDLE_KEY_TAG = "bundle_key_tag"; + private String softwareTag; + private String softwareName; + private ProgressDialog mDialog; + private boolean mInputDoubleEmpty = false; + + private CommentBar mDelegation; + + public static void show(Context context, String tag, String name) { + Intent intent = new Intent(context, SoftwareTweetActivity.class); + intent.putExtra(SoftwareTweetActivity.BUNDLE_KEY_TAG, tag); + intent.putExtra(SoftwareTweetActivity.BUNDLE_KEY_NAME, name); + context.startActivity(intent); + } + + @Override + protected int getContentView() { + return R.layout.activity_software_tweets; + } + + @Override + protected boolean initBundle(Bundle bundle) { + softwareTag = bundle.getString(BUNDLE_KEY_TAG); + softwareName = bundle.getString(BUNDLE_KEY_NAME); + return !(TextUtils.isEmpty(softwareTag) || TextUtils.isEmpty(softwareName)); + } + + @Override + protected void initWidget() { + super.initWidget(); + + mDelegation = CommentBar.delegation(this, (CoordinatorLayout) findViewById(R.id.coordinatorLayout)); + + mDelegation.getBottomSheet().setCommitListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + handleSendComment(mDelegation.getBottomSheet().getCommentText()); + } + }); + mDelegation.getBottomSheet().getEditText().setOnKeyListener(new View.OnKeyListener() { + @Override + public boolean onKey(View v, int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_DEL) { + handleKeyDel(); + } + return false; + } + }); + + mDelegation.getBottomSheet().setMentionListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (AccountHelper.isLogin()) + SelectFriendsActivity.show(SoftwareTweetActivity.this); + else + LoginActivity.show(SoftwareTweetActivity.this); + } + }); + mDelegation.getBottomSheet().hideSyncAction(); + } + + + @Override + protected void requestData() { + super.requestData(); + OSChinaApi.getSoftwareTweetList(softwareTag, mIsRefresh ? null : mBean.getNextPageToken(), mHandler); + } + + + /** + * 检查当前数据,并检查网络状况 + * + * @return 返回当前登录用户, 未登录或者未通过检查返回0 + */ + private long requestCheck() { + + if (!TDevice.hasInternet()) { + AppContext.showToastShort(R.string.tip_no_internet); + return 0; + } + if (!AccountHelper.isLogin()) { + UIHelper.showLoginActivity(this); + return 0; + } + // 返回当前登录用户ID + return AccountHelper.getUserId(); + } + + + private void handleSendComment(String content) { + long uid = requestCheck(); + if (uid == 0) + return; + + if (TextUtils.isEmpty(content)) { + AppContext.showToastShort(R.string.tip_comment_content_empty); + return; + } + + OSChinaApi.pubSoftwareTweet(String.format("#%s# %s", softwareName, content), + new TextHttpResponseHandler() { + @Override + public void onStart() { + super.onStart(); + showWaitDialog(R.string.progress_submit); + } + + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + AppContext.showToast("评论失败!"); + hideWaitDialog(); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + Type type = new TypeToken>() { + }.getType(); + + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, type); + + if (resultBean.isSuccess()) { + onRefreshing(); + mDelegation.getBottomSheet().dismiss(); + mDelegation.getBottomSheet().getEditText().setText(""); + } + hideWaitDialog(); + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + hideWaitDialog(); + } + }); + } + + private void handleKeyDel() { + + if (TextUtils.isEmpty(mDelegation.getBottomSheet().getCommentText())) { + if (mInputDoubleEmpty) { + mDelegation.getCommentText().setHint("发表评论"); + mDelegation.getBottomSheet().getEditText().setHint("发表评论"); + } else { + mInputDoubleEmpty = true; + } + } else { + mInputDoubleEmpty = false; + } + } + + + private ProgressDialog showWaitDialog(int messageId) { + String message = getResources().getString(messageId); + if (mDialog == null) { + mDialog = DialogHelper.getProgressDialog(this, message); + } + + mDialog.setMessage(message); + mDialog.show(); + + return mDialog; + } + + public void hideWaitDialog() { + ProgressDialog dialog = mDialog; + if (dialog != null) { + mDialog = null; + try { + dialog.dismiss(); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + } + + @Override + protected Type getType() { + return new TypeToken>>() { + }.getType(); + } + + @Override + protected BaseRecyclerAdapter getRecyclerAdapter() { + SoftwareTweetAdapter tweetAdapter = new SoftwareTweetAdapter(this, ONLY_FOOTER); + tweetAdapter.setOnItemLongClickListener(new BaseRecyclerAdapter.OnItemLongClickListener() { + @Override + public void onLongClick(int position, long itemId) { + + final Tweet tweet = mAdapter.getItem(position); + final long sourceId = tweet.getId(); + + long id = tweet.getAuthor().getId(); + long loginUid = AccountHelper.getUserId(); + if (id == loginUid) { + DialogHelper.getConfirmDialog(SoftwareTweetActivity.this, "删除该动弹?", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + OSChinaApi.delSoftwareTweet(sourceId, new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + Toast.makeText(SoftwareTweetActivity.this, "删除失败...", Toast.LENGTH_SHORT).show(); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + Type type = new TypeToken() { + }.getType(); + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, type); + if (resultBean.getCode() == 1) { + Toast.makeText(SoftwareTweetActivity.this, "删除成功...", Toast.LENGTH_SHORT).show(); + onRefreshing(); + } else { + Toast.makeText(SoftwareTweetActivity.this, "删除失败...", Toast.LENGTH_SHORT).show(); + } + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + } + }); + + } + }).create().show(); + } + } + }); + return tweetAdapter; + } + + @Override + protected void onItemClick(Tweet item, int position) { + super.onItemClick(item, position); + TweetDetailActivity.show(this, item); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode == RESULT_OK && data != null) { + mDelegation.getBottomSheet().handleSelectFriendsResult(data); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/tweet/activities/TopicTweetActivity.java b/app/src/main/java/net/oschina/app/improve/tweet/activities/TopicTweetActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..43ccfe9eabbd18ab4723f69164780ede713192fd --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/tweet/activities/TopicTweetActivity.java @@ -0,0 +1,242 @@ +package net.oschina.app.improve.tweet.activities; + +import android.app.Dialog; +import android.content.Context; +import android.content.Intent; +import android.support.design.widget.AppBarLayout; +import android.support.design.widget.CoordinatorLayout; +import android.support.design.widget.TabLayout; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentStatePagerAdapter; +import android.support.v4.util.Pair; +import android.support.v4.view.ViewPager; +import android.support.v7.widget.Toolbar; +import android.text.TextUtils; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import net.oschina.app.R; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.base.activities.BaseActivity; +import net.oschina.app.improve.bean.simple.TweetComment; +import net.oschina.app.improve.behavior.CommentBar; +import net.oschina.app.improve.tweet.fragments.TweetFragment; +import net.oschina.app.improve.utils.DialogHelper; +import net.oschina.app.util.UIHelper; + +import java.util.ArrayList; +import java.util.List; + +import butterknife.Bind; + +/** + * 动弹话题详情 + * Created by thanatosx on 2016/11/8. + */ + +public class TopicTweetActivity extends BaseActivity { + + @Bind(R.id.layout_coordinator) + CoordinatorLayout mLayoutCoordinator; + @Bind(R.id.layout_appbar) + AppBarLayout mLayoutAppBar; + @Bind(R.id.iv_wallpaper) + ImageView mViewWallpaper; + @Bind(R.id.tv_title) + TextView mViewTitle; + @Bind(R.id.tv_mix_title) + TextView mViewMixTitle; + @Bind(R.id.tv_count) + TextView mViewCount; + @Bind(R.id.tv_description) + TextView mViewDescription; + @Bind(R.id.toolbar) + Toolbar mToolbar; + @Bind(R.id.layout_tab) + TabLayout mLayoutTab; + @Bind(R.id.view_pager) + ViewPager mViewPager; + + EditText mViewInput; + private Dialog dialog; + private TabLayoutOffsetChangeListener mOffsetChangerListener; + private CommentBar mDelegation; + + private List> fragments; + private List replies = new ArrayList<>(); + + public static void show(Context context) { + Intent intent = new Intent(context, TopicTweetActivity.class); + context.startActivity(intent); + } + + @Override + protected int getContentView() { + return R.layout.activity_topic_tweet; + } + + @Override + protected void initWidget() { + super.initWidget(); + mToolbar.setTitle(""); + mToolbar.setSubtitle(""); + mToolbar.setNavigationIcon(R.mipmap.btn_back_normal); + setSupportActionBar(mToolbar); + mToolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + + mViewTitle.setText("#开源中国客户端#"); + mViewMixTitle.setText("#开源中国客户端#"); + mViewCount.setText("共有 212 人参与"); + mViewDescription.setText("你对开源中国客户端有什么看法呢?或者有什么好的idea想与大家分享?不要吝啬你的手指,赶快来忘记我吧!"); + mLayoutAppBar.addOnOffsetChangedListener(mOffsetChangerListener = new TabLayoutOffsetChangeListener()); + + fragments = new ArrayList<>(); + fragments.add(Pair.create("最新", TweetFragment.instantiate(TweetFragment.CATALOG_NEW))); + fragments.add(Pair.create("最热", TweetFragment.instantiate(TweetFragment.CATALOG_HOT))); + + mViewPager.setAdapter(new FragmentStatePagerAdapter(getSupportFragmentManager()) { + @Override + public Fragment getItem(int position) { + return fragments.get(position).second; + } + + @Override + public int getCount() { + return fragments.size(); + } + + @Override + public CharSequence getPageTitle(int position) { + return fragments.get(position).first; + } + }); + mLayoutTab.setupWithViewPager(mViewPager); + + mDelegation = CommentBar.delegation(this, mLayoutCoordinator); + + mDelegation.getBottomSheet().getEditText().setOnKeyListener(new View.OnKeyListener() { + @Override + public boolean onKey(View v, int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_DEL) { + handleKeyDel(); + } + return false; + } + }); + + mDelegation.getBottomSheet().showEmoji(); + mDelegation.getBottomSheet().setCommitListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + String content = mDelegation.getBottomSheet().getCommentText().replaceAll("[\\s\\n]+", " "); + if (TextUtils.isEmpty(content)) { + Toast.makeText(TopicTweetActivity.this, "请输入文字", Toast.LENGTH_SHORT).show(); + return; + } + if (!AccountHelper.isLogin()) { + UIHelper.showLoginActivity(TopicTweetActivity.this); + return; + } + if (replies != null && replies.size() > 0) + content = mViewInput.getHint() + ": " + content; + dialog = DialogHelper.getProgressDialog(TopicTweetActivity.this, "正在发表评论..."); + dialog.show(); + } + }); + + + /*mDelegation = KeyboardInputDelegation.delegation(this, mLayoutCoordinator, mViewPager); + mDelegation.setBehavior(new FloatingAutoHideDownBehavior()); + mDelegation.showEmoji(getSupportFragmentManager()); + mDelegation.setAdapter(new KeyboardInputDelegation.KeyboardInputAdapter() { + @Override + public void onSubmit(TextView v, String content) { + // TODO do on submit + } + + @Override + public void onFinalBackSpace(View v) { + // TODO remove @someone + } + });*/ + } + + private void handleKeyDel() { + if (replies == null || replies.size() == 0) return; + replies.remove(replies.size() - 1); + if (replies.size() == 0) { + mViewInput.setHint("发表评论"); + return; + } + mViewInput.setHint("回复: @" + replies.get(0).getAuthor().getName()); + if (replies.size() == 2) { + mViewInput.setHint(mViewInput.getHint() + " @" + replies.get(1).getAuthor() + .getName()); + } + } + + @Override + protected void initData() { + super.initData(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_share, menu); + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.menu_share: + // TODO share the topic + break; + } + return super.onOptionsItemSelected(item); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + switch (keyCode) { + case KeyEvent.KEYCODE_BACK: +// if (!mDelegation.onTurnBack()) return true; + break; + } + return super.onKeyDown(keyCode, event); + } + + private class TabLayoutOffsetChangeListener implements AppBarLayout.OnOffsetChangedListener { + boolean isShow = false; + int mScrollRange = -1; + + @Override + public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { + if (mScrollRange == -1) { + mScrollRange = appBarLayout.getTotalScrollRange(); + } + if (mScrollRange + verticalOffset == 0) { + mViewMixTitle.setVisibility(View.VISIBLE); + isShow = true; + } else if (isShow) { + mViewMixTitle.setVisibility(View.GONE); + isShow = false; + } + } + + public void resetRange() { + mScrollRange = -1; + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/tweet/activities/TweetDetailActivity.java b/app/src/main/java/net/oschina/app/improve/tweet/activities/TweetDetailActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..10020bc04a42ad3cbe6f9bc86a1151ef90105fe4 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/tweet/activities/TweetDetailActivity.java @@ -0,0 +1,608 @@ +package net.oschina.app.improve.tweet.activities; + +import android.app.Dialog; +import android.content.Context; +import android.content.Intent; +import android.graphics.drawable.AnimationDrawable; +import android.os.Bundle; +import android.support.design.widget.CoordinatorLayout; +import android.support.v7.app.AlertDialog; +import android.support.v7.widget.Toolbar; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.TextUtils; +import android.text.method.LinkMovementMethod; +import android.text.style.ForegroundColorSpan; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.AppContext; +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.account.activity.LoginActivity; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.base.activities.BaseActivity; +import net.oschina.app.improve.bean.Tweet; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.bean.simple.About; +import net.oschina.app.improve.bean.simple.TweetComment; +import net.oschina.app.improve.bean.simple.TweetLike; +import net.oschina.app.improve.behavior.CommentBar; +import net.oschina.app.improve.dialog.ShareDialogBuilder; +import net.oschina.app.improve.tweet.contract.TweetDetailContract; +import net.oschina.app.improve.tweet.service.TweetPublishService; +import net.oschina.app.improve.utils.AssimilateUtils; +import net.oschina.app.improve.utils.DialogHelper; +import net.oschina.app.improve.widget.TweetPicturesLayout; +import net.oschina.app.ui.SelectFriendsActivity; +import net.oschina.app.util.PlatfromUtil; +import net.oschina.app.util.StringUtils; +import net.oschina.app.util.UIHelper; +import net.oschina.app.viewpagerfragment.TweetDetailViewPagerFragment; +import net.oschina.app.widget.RecordButtonUtil; + +import java.util.ArrayList; +import java.util.List; + +import butterknife.Bind; +import butterknife.OnClick; +import cz.msebera.android.httpclient.Header; +import de.hdodenhof.circleimageview.CircleImageView; + +/** + * 动弹详情 + * Created by thanatos + * on 16/6/13. + */ +@SuppressWarnings("deprecation") +public class TweetDetailActivity extends BaseActivity implements TweetDetailContract.Operator { + + public static final String BUNDLE_KEY_TWEET = "BUNDLE_KEY_TWEET"; + public static final String BUNDLE_KEY_TWEET_ID = "BUNDLE_KEY_TWEET_ID"; + + @Bind(R.id.iv_portrait) + CircleImageView ivPortrait; + @Bind(R.id.tv_nick) + TextView tvNick; + @Bind(R.id.tv_time) + TextView tvTime; + @Bind(R.id.tv_client) + TextView tvClient; + @Bind(R.id.iv_thumbup) + ImageView ivThumbup; + @Bind(R.id.layout_coordinator) + CoordinatorLayout mCoordinatorLayout; + @Bind(R.id.fragment_container) + FrameLayout mFrameLayout; + @Bind(R.id.tweet_img_record) + ImageView mImgRecord; + @Bind(R.id.tweet_tv_record) + TextView mSecondRecord; + @Bind(R.id.tweet_bg_record) + RelativeLayout mRecordLayout; + @Bind(R.id.tv_content) + TextView mContent; + @Bind(R.id.tweet_pics_layout) + TweetPicturesLayout mLayoutGrid; + @Bind(R.id.toolbar) + Toolbar mToolbar; + @Bind(R.id.tv_ref_title) + TextView mViewRefTitle; + @Bind(R.id.tv_ref_content) + TextView mViewRefContent; + @Bind(R.id.layout_ref_images) + TweetPicturesLayout mLayoutRefImages; + @Bind(R.id.iv_dispatch) + ImageView mViewDispatch; + @Bind(R.id.layout_ref) + LinearLayout mLayoutRef; + + EditText mViewInput; + + private Tweet tweet; + private List replies = new ArrayList<>(); + private Dialog dialog; + private RecordButtonUtil mRecordUtil; + private TextHttpResponseHandler publishAdmireHandler; + private TextHttpResponseHandler publishCommentHandler; + + private TweetDetailContract.ICmnView mCmnViewImp; + private TweetDetailContract.IThumbupView mThumbupViewImp; + private TweetDetailContract.IAgencyView mAgencyViewImp; + + private CommentBar mDelegation; + private boolean mInputDoubleEmpty = false; + + private View.OnClickListener onPortraitClickListener; + private ShareDialogBuilder mShareDialogBuilder; + private AlertDialog alertDialog; + + public static void show(Context context, Tweet tweet) { + Intent intent = new Intent(context, TweetDetailActivity.class); + intent.putExtra(BUNDLE_KEY_TWEET, tweet); + context.startActivity(intent); + } + + public static void show(Context context, long id) { + Tweet tweet = new Tweet(); + tweet.setId(id); + show(context, tweet); + } + + @Override + protected int getContentView() { + return R.layout.activity_tweet_detail; + } + + @Override + protected boolean initBundle(Bundle bundle) { + tweet = (Tweet) getIntent().getSerializableExtra(BUNDLE_KEY_TWEET); + if (tweet == null) { + Toast.makeText(this, "对象没找到", Toast.LENGTH_SHORT).show(); + return false; + } + return super.initBundle(bundle); + } + + protected void initData() { + // admire tweet + publishAdmireHandler = new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, + Throwable throwable) { + Toast.makeText(TweetDetailActivity.this, ivThumbup.isSelected() ? "取消失败" : + "点赞失败", Toast.LENGTH_SHORT).show(); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + ResultBean result = AppOperator.createGson().fromJson( + responseString, new TypeToken>() { + }.getType()); + if (result != null && result.isSuccess()) { + ivThumbup.setSelected(result.getResult().isLiked()); + mThumbupViewImp.onLikeSuccess(result.getResult().isLiked(), null); + } else { + onFailure(statusCode, headers, responseString, null); + } + } + + @Override + public void onFinish() { + super.onFinish(); + dismissDialog(); + } + }; + + // publish tweet comment + publishCommentHandler = new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, + Throwable throwable) { + Toast.makeText(TweetDetailActivity.this, "评论失败", Toast.LENGTH_SHORT).show(); + dismissDialog(); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + mCmnViewImp.onCommentSuccess(null); + replies.clear(); // 清除 + + if (mDelegation.getBottomSheet().isSyncToTweet()) { + Tweet tempTweet = tweet; + if (tempTweet == null) return; + TweetPublishService.startActionPublish(TweetDetailActivity.this + , mDelegation.getBottomSheet().getCommentText(), null, + About.buildShare(tempTweet.getId(), OSChinaApi.COMMENT_TWEET)); + } + + mViewInput.setHint("添加评论"); + mDelegation.setCommentHint("添加评论"); + mDelegation.getBottomSheet().getEditText().setText(""); + mDelegation.getBottomSheet().getEditText().setHint("添加评论"); + mViewInput.setText(null); + mDelegation.getBottomSheet().dismiss(); + dismissDialog(); + } + }; + + OSChinaApi.getTweetDetail(tweet.getId(), new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, + Throwable throwable) { + Toast.makeText(TweetDetailActivity.this, "获取数据失败", Toast.LENGTH_SHORT).show(); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + ResultBean result = AppOperator.createGson().fromJson( + responseString, new TypeToken>() { + }.getType()); + if (result.isSuccess()) { + if (result.getResult() == null) { + AppContext.showToast(R.string.tweet_detail_data_null); + finish(); + return; + } + tweet = result.getResult(); + mAgencyViewImp.resetCmnCount(tweet.getCommentCount()); + mAgencyViewImp.resetLikeCount(tweet.getLikeCount()); + setupDetailView(); + } else { + onFailure(500, headers, "妈的智障", null); + } + } + }); + + } + + protected void initWidget() { + mToolbar.setTitle("动弹详情"); + setSupportActionBar(mToolbar); + mToolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + supportFinishAfterTransition(); + } + }); + + mDelegation = CommentBar.delegation(this, mCoordinatorLayout); + + mDelegation.getBottomSheet().getEditText().setOnKeyListener(new View.OnKeyListener() { + @Override + public boolean onKey(View v, int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_DEL && event.getAction() == KeyEvent.ACTION_DOWN) { + handleKeyDel(); + } + return false; + } + }); + + mDelegation.hideShare(); + mDelegation.hideFav(); + + mDelegation.getBottomSheet().setMentionListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (AccountHelper.isLogin()) + SelectFriendsActivity.show(TweetDetailActivity.this); + else + LoginActivity.show(TweetDetailActivity.this); + } + }); + + mDelegation.getBottomSheet().showEmoji(); + mDelegation.getBottomSheet().hideSyncAction(); + mDelegation.getBottomSheet().setCommitListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + String content = mDelegation.getBottomSheet().getCommentText().replaceAll("[\\s\\n]+", " "); + if (TextUtils.isEmpty(content)) { + Toast.makeText(TweetDetailActivity.this, "请输入文字", Toast.LENGTH_SHORT).show(); + return; + } + if (!AccountHelper.isLogin()) { + UIHelper.showLoginActivity(TweetDetailActivity.this); + return; + } + if (replies != null && replies.size() > 0) + content = mViewInput.getHint() + ": " + content; + dialog = DialogHelper.getProgressDialog(TweetDetailActivity.this, "正在发表评论..."); + dialog.show(); + OSChinaApi.pubTweetComment(tweet.getId(), content, 0, publishCommentHandler); + } + }); + + mViewInput = mDelegation.getBottomSheet().getEditText(); + + resolveVoice(); + setupDetailView(); + + TweetDetailViewPagerFragment mPagerFrag = TweetDetailViewPagerFragment.instantiate(this); + mCmnViewImp = mPagerFrag.getCommentViewHandler(); + mThumbupViewImp = mPagerFrag.getThumbupViewHandler(); + mAgencyViewImp = mPagerFrag.getAgencyViewHandler(); + getSupportFragmentManager().beginTransaction() + .replace(R.id.fragment_container, mPagerFrag) + .commit(); + } + + private void resolveVoice() { + if (tweet == null || tweet.getAudio() == null || tweet.getAudio().length == 0) return; + mRecordLayout.setVisibility(View.VISIBLE); + final AnimationDrawable drawable = (AnimationDrawable) mImgRecord.getBackground(); + mRecordLayout.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (tweet == null) return; + getRecordUtil().startPlay(tweet.getAudio()[0].getHref(), mSecondRecord); + } + }); + getRecordUtil().setOnPlayListener(new RecordButtonUtil.OnPlayListener() { + @Override + public void stopPlay() { + drawable.stop(); + mImgRecord.setBackgroundDrawable(drawable.getFrame(0)); + } + + @Override + public void starPlay() { + drawable.start(); + mImgRecord.setBackgroundDrawable(drawable); + } + }); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_share, menu); + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.menu_share: + if (tweet == null || tweet.getId() <= 0) break; + + String content = tweet.getContent().trim(); + if (content.length() > 10) + content = content.substring(0, 10); + + if (mShareDialogBuilder == null) + mShareDialogBuilder = ShareDialogBuilder.with(this) + .title(content + " - 开源中国社区 ") + .content(tweet.getContent()) + .url(tweet.getHref()) + .build(); + if (alertDialog == null) + alertDialog = mShareDialogBuilder.create(); + alertDialog.show(); + + break; + } + return super.onOptionsItemSelected(item); + } + + private RecordButtonUtil getRecordUtil() { + if (mRecordUtil == null) { + mRecordUtil = new RecordButtonUtil(); + } + return mRecordUtil; + } + + private void dismissDialog() { + if (dialog == null) return; + dialog.dismiss(); + dialog = null; + } + + /** + * 填充数据 + */ + private void setupDetailView() { + // 有可能传入的tweet只有id这一个值 + if (tweet == null || isDestroy()) + return; + if (tweet.getAuthor() != null) { + if (TextUtils.isEmpty(tweet.getAuthor().getPortrait())) { + ivPortrait.setImageResource(R.mipmap.widget_dface); + } else { + getImageLoader() + .load(tweet.getAuthor().getPortrait()) + .asBitmap() + .placeholder(getResources().getDrawable(R.mipmap.widget_dface)) + .error(getResources().getDrawable(R.mipmap.widget_dface)) + .into(ivPortrait); + } + ivPortrait.setOnClickListener(getOnPortraitClickListener()); + tvNick.setText(tweet.getAuthor().getName()); + } + if (!TextUtils.isEmpty(tweet.getPubDate())) + tvTime.setText(StringUtils.formatSomeAgo(tweet.getPubDate())); + PlatfromUtil.setPlatFromString(tvClient, tweet.getAppClient()); + if (tweet.isLiked()) { + ivThumbup.setSelected(true); + } else { + ivThumbup.setSelected(false); + } + if (!TextUtils.isEmpty(tweet.getContent())) { + String content = tweet.getContent().replaceAll("[\n\\s]+", " "); + mContent.setText(AssimilateUtils.assimilate(this, content)); + mContent.setMovementMethod(LinkMovementMethod.getInstance()); + } + + mLayoutGrid.setImage(tweet.getImages()); + + /* -- about reference -- */ + if (tweet.getAbout() != null) { + mLayoutRef.setVisibility(View.VISIBLE); + About about = tweet.getAbout(); + mLayoutRefImages.setImage(about.getImages()); + + if (!About.check(about)) { + mViewRefTitle.setVisibility(View.VISIBLE); + mViewRefTitle.setText("不存在或已删除的内容"); + mViewRefContent.setText("抱歉,该内容不存在或已被删除"); + } else { + if (about.getType() == OSChinaApi.COMMENT_TWEET) { + mViewRefTitle.setVisibility(View.GONE); + String aname = "@" + about.getTitle(); + String cnt = about.getContent(); + Spannable spannable = AssimilateUtils.assimilate(this, cnt); + SpannableStringBuilder builder = new SpannableStringBuilder(); + builder.append(aname + ": "); + builder.append(spannable); + ForegroundColorSpan span = new ForegroundColorSpan( + getResources().getColor(R.color.day_colorPrimary)); + builder.setSpan(span, 0, aname.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); + mViewRefContent.setText(builder); + } else { + mViewRefTitle.setVisibility(View.VISIBLE); + mViewRefTitle.setText(about.getTitle()); + mViewRefContent.setText(about.getContent()); + } + } + } else { + mLayoutRef.setVisibility(View.GONE); + } + } + + private View.OnClickListener getOnPortraitClickListener() { + if (onPortraitClickListener == null) { + onPortraitClickListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + UIHelper.showUserCenter(TweetDetailActivity.this, tweet.getAuthor().getId(), + tweet.getAuthor().getName()); + } + }; + } + return onPortraitClickListener; + } + + @Override + public Tweet getTweetDetail() { + return tweet; + } + + @Override + public void toReply(TweetComment comment) { + if (checkLogin()) return; + if (replies.size() < 5) { + for (TweetComment cmm : replies) { + if (cmm.getAuthor().getId() == comment.getAuthor().getId()) { + this.mDelegation.performClick(); + return; + } + } + if (replies.size() == 0) { + mViewInput.setHint("回复: @" + comment.getAuthor().getName()); + mDelegation.setCommentHint(mViewInput.getHint().toString()); + } else { + mViewInput.setHint(mViewInput.getHint() + " @" + comment.getAuthor().getName()); + mDelegation.setCommentHint(mViewInput.getHint().toString()); + } + this.replies.add(comment); + } + this.mDelegation.performClick(); + } + + @Override + public void onScroll() { + if (mDelegation != null) mDelegation.getBottomSheet().dismiss(); + } + + @OnClick(R.id.iv_thumbup) + void onClickThumbUp() { + if (checkLogin()) return; + this.dialog = DialogHelper.getProgressDialog(this, "正在提交请求..."); + this.dialog.show(); + OSChinaApi.reverseTweetLike(tweet.getId(), publishAdmireHandler); + } + + @OnClick(R.id.layout_ref) + void onClickRef() { + if (tweet.getAbout() == null) return; + UIHelper.showDetail(this, tweet.getAbout().getType(), tweet.getAbout().getId(), null); + } + + @OnClick(R.id.iv_comment) + void onClickComment() { + if (checkLogin()) return; + mDelegation.getBottomSheet().show("发表评论"); + } + + @OnClick(R.id.iv_dispatch) + void onClickTransmit() { + if (tweet == null || tweet.getId() <= 0) return; + + String content = null; + About.Share share; + if (tweet.getAbout() == null) { + share = About.buildShare(tweet.getId(), OSChinaApi.CATALOG_TWEET); + share.title = tweet.getAuthor().getName(); + share.content = tweet.getContent(); + } else { + share = About.buildShare(tweet.getAbout()); + content = "//@" + tweet.getAuthor().getName() + " :" + tweet.getContent(); + content = AssimilateUtils.clearHtmlTag(content).toString(); + } + share.commitTweetId = tweet.getId(); + share.fromTweetId = tweet.getId(); + TweetPublishActivity.show(this, null, content, share); + } + + private boolean checkLogin() { + if (!AccountHelper.isLogin()) { + LoginActivity.show(this); + return true; + } + return false; + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + switch (keyCode) { + case KeyEvent.KEYCODE_BACK: +// if (!mDelegation.onTurnBack()) return true; + break; + } + return super.onKeyDown(keyCode, event); + } + + private void handleKeyDel() { + if (replies == null || replies.size() == 0) return; + if (TextUtils.isEmpty(mDelegation.getBottomSheet().getCommentText())) { + if (mInputDoubleEmpty) { + replies.remove(replies.size() - 1); + if (replies.size() == 0) { + mViewInput.setHint("发表评论"); + mDelegation.setCommentHint(mViewInput.getHint().toString()); + return; + } + mViewInput.setHint("回复: @" + replies.get(0).getAuthor().getName()); + for (int i = 1; i < replies.size(); i++) { + mViewInput.setHint(mViewInput.getHint() + " @" + replies.get(i).getAuthor() + .getName()); + } + } else { + mInputDoubleEmpty = true; + } + } else { + mInputDoubleEmpty = false; + } + + } + + @Override + protected void onStop() { + super.onStop(); + if (mShareDialogBuilder != null) { + mShareDialogBuilder.cancelLoading(); + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode == RESULT_OK && data != null) { + mDelegation.getBottomSheet().handleSelectFriendsResult(data); + mDelegation.setCommentHint(mDelegation.getBottomSheet().getEditText().getHint().toString()); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/tweet/activities/TweetPublishActivity.java b/app/src/main/java/net/oschina/app/improve/tweet/activities/TweetPublishActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..42c151d9ea4a90cd6e8d1c3fabc2c21b597271a7 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/tweet/activities/TweetPublishActivity.java @@ -0,0 +1,258 @@ +package net.oschina.app.improve.tweet.activities; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.provider.MediaStore; +import android.support.annotation.Size; +import android.support.v4.app.FragmentTransaction; +import android.text.TextUtils; +import android.view.View; +import android.view.WindowManager; + +import net.oschina.app.BuildConfig; +import net.oschina.app.R; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.base.activities.BaseBackActivity; +import net.oschina.app.improve.bean.simple.About; +import net.oschina.app.improve.tweet.contract.TweetPublishContract; +import net.oschina.app.improve.tweet.fragments.TweetPublishFragment; +import net.oschina.app.improve.tweet.service.TweetPublishService; +import net.oschina.app.util.UIHelper; +import net.oschina.common.utils.CollectionUtil; + +import java.io.File; +import java.util.ArrayList; + +/** + * Created by JuQiu + * on 16/8/22. + */ +public class TweetPublishActivity extends BaseBackActivity { + private TweetPublishContract.View mView; + + public static void show(Context context) { + show(context, null); + } + + public static void show(Context context, View view) { + show(context, view, null); + } + + public static void show(Context context, View view, String defaultContent) { + show(context, view, defaultContent, null); + } + + public static void show(Context context, View view, String defaultContent, About.Share share) { + int[] location = new int[]{0, 0}; + int[] size = new int[]{0, 0}; + + if (view != null) { + view.getLocationOnScreen(location); + size[0] = view.getWidth(); + size[1] = view.getHeight(); + } + + show(context, location, size, defaultContent, share); + } + + + public static void show(Context context, @Size(2) int[] viewLocationOnScreen, + @Size(2) int[] viewSize, String defaultContent, About.Share share) { + // Check login before show + if (!AccountHelper.isLogin()) { + UIHelper.showLoginActivity(context); + return; + } + + Intent intent = new Intent(context, TweetPublishActivity.class); + + if (viewLocationOnScreen != null) { + intent.putExtra("location", viewLocationOnScreen); + } + if (viewSize != null) { + intent.putExtra("size", viewSize); + } + if (defaultContent != null) { + intent.putExtra("defaultContent", defaultContent); + } + if (share != null) { + intent.putExtra("aboutShare", share); + } + + context.startActivity(intent); + } + + @Override + protected int getContentView() { + // hide the software + // getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); + return R.layout.activity_tweet_publish; + } + + @SuppressWarnings({"MismatchedQueryAndUpdateOfCollection", "unchecked", "ResultOfMethodCallIgnored"}) + @Override + protected void initWidget() { + super.initWidget(); + getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT); + + Intent intent = getIntent(); + Bundle bundle = intent.getExtras(); + // Read other data + readFastShareByOther(bundle); + + TweetPublishFragment fragment = new TweetPublishFragment(); + // init the args bounds + fragment.setArguments(bundle); + FragmentTransaction trans = getSupportFragmentManager() + .beginTransaction(); + trans.replace(R.id.activity_tweet_publish, fragment); + trans.commit(); + mView = fragment; + } + + /** + * 读取快速分享到当前界面的内容 + * + * @param bundle 需要写入源 + */ + private void readFastShareByOther(Bundle bundle) { + // Check + if (bundle == null || getIntent() == null) + return; + Intent intent = getIntent(); + String type = intent.getType(); + if (TextUtils.isEmpty(type)) + return; + + //判断当前分享的内容是文本,还是图片 + if ("text/plain".equals(type)) { + String text = intent.getStringExtra(Intent.EXTRA_TEXT); + bundle.putString("defaultContent", text); + } else if ("image/*".equals(type)) { + ArrayList uris = new ArrayList<>(); + Object obj = intent.getExtras().get(Intent.EXTRA_STREAM); + if (obj instanceof Uri) { + Uri uri = (Uri) obj; + String decodePath = decodePath(uri); + if (decodePath != null) + uris.add(decodePath); + } else { + try { + @SuppressWarnings("unchecked") + ArrayList list = (ArrayList) obj; + //大于9张图片的分享,直接只使用前9张 + if (list != null && list.size() > 0) { + for (int i = 0, len = list.size(); i < len; i++) { + if (i > 9) { + break; + } + String decodePath = decodePath(list.get(i)); + if (decodePath != null) + uris.add(decodePath); + } + } + } catch (Exception e) { + if (BuildConfig.DEBUG) + e.printStackTrace(); + } + } + if (uris.size() > 0) { + String[] paths = CollectionUtil.toArray(uris, String.class); + bundle.putStringArray("defaultImages", paths); + } + } + } + + /** + * 通过uri当中的唯一id搜索本地相册图片,是否真的存在。然后返回真实的path路径 + * + * @param uri rui + * @return path + */ + private String decodePath(Uri uri) { + String decodePath = null; + String uriPath = uri.toString(); + int id = Integer.parseInt(uriPath.substring(uriPath.lastIndexOf("/") + 1, uriPath.length())); + + Uri tempUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; + String[] projection = {MediaStore.Images.Media.DATA}; + String selection = MediaStore.Images.Media._ID + "=?"; + String[] selectionArgs = {id + ""}; + + Cursor cursor = getContentResolver().query(tempUri, projection, selection, selectionArgs, null); + try { + while (cursor != null && cursor.moveToNext()) { + String temp = cursor.getString(0); + File file = new File(temp); + if (file.exists()) { + decodePath = temp; + } + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (cursor != null && !cursor.isClosed()) + cursor.close(); + } + return decodePath; + } + + @Override + protected void initData() { + super.initData(); + // before the fragment show + registerPublishStateReceiver(); + } + + @Override + protected void onDestroy() { + unRegisterPublishStateReceiver(); + super.onDestroy(); + } + + private void registerPublishStateReceiver() { + if (mPublishStateReceiver != null) + return; + IntentFilter intentFilter = new IntentFilter(TweetPublishService.ACTION_RECEIVER_SEARCH_FAILED); + BroadcastReceiver receiver = new SearchReceiver(); + registerReceiver(receiver, intentFilter); + mPublishStateReceiver = receiver; + + // start search + TweetPublishService.startActionSearchFailed(this); + } + + private void unRegisterPublishStateReceiver() { + final BroadcastReceiver receiver = mPublishStateReceiver; + mPublishStateReceiver = null; + if (receiver != null) + unregisterReceiver(receiver); + } + + private BroadcastReceiver mPublishStateReceiver; + + private class SearchReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + if (TweetPublishService.ACTION_RECEIVER_SEARCH_FAILED.equals(intent.getAction())) { + String[] ids = intent.getStringArrayExtra(TweetPublishService.EXTRA_IDS); + if (ids == null || ids.length == 0) + return; + TweetPublishQueueActivity.show(TweetPublishActivity.this, ids); + } + } + } + + @Override + public void onBackPressed() { + //super.onBackPressed(); + if (mView != null) { + mView.getOperator().onBack(); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/oschina/app/improve/tweet/activities/TweetPublishQueueActivity.java b/app/src/main/java/net/oschina/app/improve/tweet/activities/TweetPublishQueueActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..f83ae677c67df64535a8d2c1bb0ccde85677a7a2 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/tweet/activities/TweetPublishQueueActivity.java @@ -0,0 +1,116 @@ +package net.oschina.app.improve.tweet.activities; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.widget.TextView; + +import net.oschina.app.R; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.base.activities.BaseBackActivity; +import net.oschina.app.improve.tweet.adapter.TweetQueueAdapter; +import net.oschina.app.improve.tweet.service.TweetPublishCache; +import net.oschina.app.improve.tweet.service.TweetPublishModel; +import net.oschina.app.improve.tweet.service.TweetPublishService; +import net.qiujuer.genius.ui.widget.Loading; + +import java.util.ArrayList; +import java.util.List; + +import butterknife.Bind; +import butterknife.OnClick; + +public class TweetPublishQueueActivity extends BaseBackActivity implements TweetQueueAdapter.Callback, View.OnClickListener { + @Bind(R.id.loading) + Loading mLoading; + @Bind(R.id.txt_title) + TextView mTitle; + @Bind(R.id.recycler) + RecyclerView mRecycler; + private TweetQueueAdapter mAdapter; + + public static void show(Context context, String[] ids) { + Intent intent = new Intent(context, TweetPublishQueueActivity.class); + intent.putExtra(TweetPublishService.EXTRA_IDS, ids); + context.startActivity(intent); + } + + @Override + protected int getContentView() { + return R.layout.activity_tweet_publish_queue; + } + + @Override + protected void initWidget() { + super.initWidget(); + mRecycler.setLayoutManager(new LinearLayoutManager(this)); + mAdapter = new TweetQueueAdapter(this); + mRecycler.setAdapter(mAdapter); + } + + @Override + protected boolean initBundle(Bundle bundle) { + if (bundle != null) { + final String[] ids = bundle.getStringArray(TweetPublishService.EXTRA_IDS); + if (ids != null && ids.length > 0) { + AppOperator.runOnThread(new Runnable() { + @Override + public void run() { + Context context = getApplicationContext(); + List models = new ArrayList(); + for (String str : ids) { + TweetPublishModel model = TweetPublishCache.get(context, str); + if (model != null) + models.add(model); + } + if (models.size() > 0) + addData(models); + else + finish(); + } + }); + return true; + } + } + return false; + } + + private void addData(final List models) { + runOnUiThread(new Runnable() { + @Override + public void run() { + mAdapter.add(models); + mLoading.setVisibility(View.GONE); + mTitle.setVisibility(View.VISIBLE); + mRecycler.setVisibility(View.VISIBLE); + + mTitle.setText(String.format("『%s』Todo", models.size())); + } + }); + } + + @Override + public void onClickContinue(TweetPublishModel model) { + TweetPublishService.startActionContinue(this, model.getId()); + if (mAdapter.getItemCount() == 0) + finish(); + } + + @Override + public void onClickDelete(TweetPublishModel model) { + TweetPublishService.startActionDelete(this, model.getId()); + if (mAdapter.getItemCount() == 0) + finish(); + } + + @OnClick(R.id.icon_back) + @Override + public void onClick(View v) { + if (v.getId() == R.id.icon_back) { + onSupportNavigateUp(); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/tweet/adapter/SoftwareTweetAdapter.java b/app/src/main/java/net/oschina/app/improve/tweet/adapter/SoftwareTweetAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..c9e6b37eb2aee9784dd23abcad2d60b33d84d468 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/tweet/adapter/SoftwareTweetAdapter.java @@ -0,0 +1,180 @@ +package net.oschina.app.improve.tweet.adapter; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.RequestManager; +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.AppContext; +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.bean.Tweet; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.bean.simple.TweetLikeReverse; +import net.oschina.app.improve.comment.CommentsUtil; +import net.oschina.app.improve.user.activities.OtherUserHomeActivity; +import net.oschina.app.util.ImageLoader; +import net.oschina.app.util.PlatfromUtil; +import net.oschina.app.util.StringUtils; +import net.oschina.app.util.TDevice; +import net.oschina.app.util.UIHelper; +import net.oschina.app.widget.TweetTextView; + +import java.lang.reflect.Type; + +import butterknife.Bind; +import butterknife.ButterKnife; +import cz.msebera.android.httpclient.Header; +import de.hdodenhof.circleimageview.CircleImageView; + +/** + * Created by fei + * on 2016/7/20. + */ +public class SoftwareTweetAdapter extends BaseRecyclerAdapter implements View.OnClickListener { + + private RequestManager requestManager; + + public SoftwareTweetAdapter(Context context, int mode) { + super(context, mode); + setState(BaseRecyclerAdapter.STATE_LOADING, false); + requestManager = Glide.with(context); + } + + @Override + protected RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type) { + return new SoftwareTweetViewHolder(mInflater.inflate(R.layout.item_list_tweet_improve, parent, false)); + } + + @SuppressWarnings("deprecation") + @Override + protected void onBindDefaultViewHolder(RecyclerView.ViewHolder holder, Tweet item, int position) { + SoftwareTweetViewHolder vh = (SoftwareTweetViewHolder) holder; + + CircleImageView icon = vh.icon; + icon.setTag(R.id.iv_tweet_face, position); + ImageLoader.loadImage(requestManager, vh.icon, item.getAuthor().getPortrait(), R.mipmap.widget_dface); + vh.icon.setOnClickListener(this); + vh.name.setText(item.getAuthor().getName()); + CommentsUtil.formatHtml(mContext.getResources(), vh.content, item.getContent()); + vh.pubTime.setText(StringUtils.formatSomeAgo(item.getPubDate())); + PlatfromUtil.setPlatFromString(vh.deviceType, item.getAppClient()); + boolean liked = item.isLiked(); + if (liked) { + vh.likeStatus.setImageResource(R.mipmap.ic_thumbup_actived); + } else { + vh.likeStatus.setImageResource(R.mipmap.ic_thumb_normal); + } + vh.likeStatus.setTag(position); + vh.likeStatus.setOnClickListener(this); + vh.likeCount.setText(item.getLikeCount() + ""); + vh.commentCount.setText(item.getCommentCount() + ""); + + } + + @Override + public void setOnItemClickListener(OnItemClickListener onItemClickListener) { + super.setOnItemClickListener(onItemClickListener); + + } + + @Override + public void onClick(View v) { + int id = v.getId(); + switch (id) { + case R.id.iv_tweet_face: + int p = (int) v.getTag(R.id.iv_tweet_face); + final Tweet item = getItem(p); + OtherUserHomeActivity.show(mContext, item.getAuthor()); + break; + case R.id.iv_like_state: + int position = (int) v.getTag(); + final Tweet tempItem = getItem(position); + requestEventDispatcher(tempItem); + break; + default: + break; + } + } + + /** + * + */ + private void requestEventDispatcher(final Tweet item) { + + if (!AccountHelper.isLogin()) { + UIHelper.showLoginActivity(mContext); + return; + } + if (!TDevice.hasInternet()) { + AppContext.showToastShort(R.string.tip_no_internet); + return; + } + + OSChinaApi.pubSoftwareLike(item.getId(), new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + Toast.makeText(mContext, "操作失败...", Toast.LENGTH_SHORT).show(); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + Type type = new TypeToken>() { + }.getType(); + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, type); + if (resultBean.getCode() == 1) { + TweetLikeReverse result = resultBean.getResult(); + boolean like = result.isLiked(); + item.setLiked(like); + int likeCount = item.getLikeCount(); + item.setLikeCount((!item.isLiked() ? likeCount - 1 : likeCount + 1)); + notifyDataSetChanged(); + } else { + Toast.makeText(mContext, "操作失败...", Toast.LENGTH_SHORT).show(); + } + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + } + }); + + } + + static class SoftwareTweetViewHolder extends RecyclerView.ViewHolder { + + @Bind(R.id.iv_tweet_face) + CircleImageView icon; + @Bind(R.id.tv_tweet_name) + TextView name; + @Bind(R.id.tweet_item) + TweetTextView content; + @Bind(R.id.tv_tweet_time) + TextView pubTime; + @Bind(R.id.tv_tweet_platform) + TextView deviceType; + @Bind(R.id.iv_like_state) + ImageView likeStatus; + @Bind(R.id.tv_tweet_like_count) + TextView likeCount; + @Bind(R.id.tv_tweet_comment_count) + TextView commentCount; + + SoftwareTweetViewHolder(View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/tweet/adapter/TopicTweetAdapter.java b/app/src/main/java/net/oschina/app/improve/tweet/adapter/TopicTweetAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..f17b31b5097f35a59ff66188f700405d6a85d52f --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/tweet/adapter/TopicTweetAdapter.java @@ -0,0 +1,84 @@ +package net.oschina.app.improve.tweet.adapter; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import net.oschina.app.R; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.tweet.activities.TopicTweetActivity; +import net.oschina.app.util.TLog; + +import butterknife.Bind; +import butterknife.ButterKnife; + +/** + * Created by thanatosx on 2016/11/7. + */ + +public class TopicTweetAdapter extends BaseRecyclerAdapter implements View.OnClickListener { + + private static final int[] images = { + R.mipmap.bg_topic_1, R.mipmap.bg_topic_2, R.mipmap.bg_topic_3, + R.mipmap.bg_topic_4, R.mipmap.bg_topic_5 + }; + + public TopicTweetAdapter(Context context) { + super(context, ONLY_FOOTER); + for (int i = 0; i < 10; i++) { + addItem(""); + } + } + + @Override + protected RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type) { + return new ViewHolder(LayoutInflater.from(mContext).inflate( + R.layout.list_item_topic_tweet, parent, false)); + } + + @Override + protected void onBindDefaultViewHolder(RecyclerView.ViewHolder h, Object item, int position) { + ViewHolder holder = (ViewHolder) h; + holder.mViewWallpaper.setImageResource(images[position % 5]); + holder.mLayoutItem1.setVisibility(View.VISIBLE); + holder.mLayoutItem2.setVisibility(View.VISIBLE); + holder.mLayoutItem3.setVisibility(View.VISIBLE); + } + + @Override + public void onClick(View v) { + TLog.d("oschina", "------onClick-----"); + TopicTweetActivity.show(v.getContext()); + } + + public class ViewHolder extends RecyclerView.ViewHolder { + + @Bind(R.id.iv_wallpaper) + ImageView mViewWallpaper; + @Bind(R.id.layout_item_1) + LinearLayout mLayoutItem1; + @Bind(R.id.layout_item_2) + LinearLayout mLayoutItem2; + @Bind(R.id.layout_item_3) + LinearLayout mLayoutItem3; + @Bind(R.id.layout_bottom) + RelativeLayout mLayoutBottom; + @Bind(R.id.tv_count) + TextView mViewCount; + + @Bind(R.id.layout_wrapper) + LinearLayout mLayoutWrapper; + + public ViewHolder(View view) { + super(view); + ButterKnife.bind(this, view); + mLayoutWrapper.setOnClickListener(TopicTweetAdapter.this); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/tweet/adapter/TweetAdapter.java b/app/src/main/java/net/oschina/app/improve/tweet/adapter/TweetAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..d18c2af489772a2d7c0320ac21650ade6426df46 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/tweet/adapter/TweetAdapter.java @@ -0,0 +1,178 @@ +package net.oschina.app.improve.tweet.adapter; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.TextUtils; +import android.text.method.LinkMovementMethod; +import android.text.style.ImageSpan; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.R; +import net.oschina.app.adapter.ViewHolder; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.emoji.InputHelper; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.account.activity.LoginActivity; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.base.adapter.BaseListAdapter; +import net.oschina.app.improve.bean.Tweet; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.bean.simple.TweetLikeReverse; +import net.oschina.app.improve.user.activities.OtherUserHomeActivity; +import net.oschina.app.improve.utils.AssimilateUtils; +import net.oschina.app.improve.widget.TweetPicturesLayout; +import net.oschina.app.util.ImageUtils; +import net.oschina.app.util.PlatfromUtil; +import net.oschina.app.util.StringUtils; +import net.oschina.app.widget.TweetTextView; + +import org.kymjs.kjframe.utils.DensityUtils; + +import java.lang.reflect.Type; + +import cz.msebera.android.httpclient.Header; +import de.hdodenhof.circleimageview.CircleImageView; + +/** + * 动弹列表适配器 + * Created by huanghaibin_dev + * on 2016/7/18. + */ +public class TweetAdapter extends BaseListAdapter { + private Bitmap recordBitmap; + private OnTweetLikeClickListener listener; + + + public TweetAdapter(Callback callback) { + super(callback); + initListener(); + } + + private void initListener() { + listener = new OnTweetLikeClickListener() { + @Override + public void onClick(View v, int position) { + if (!AccountHelper.isLogin()) { + LoginActivity.show(mCallback.getContext()); + return; + } + OSChinaApi.reverseTweetLike(getItem(position).getId(), new TweetLikedHandler(position)); + } + }; + } + + private void initRecordImg(Context cxt) { + recordBitmap = BitmapFactory.decodeResource(cxt.getResources(), + R.mipmap.audio3); + recordBitmap = ImageUtils.zoomBitmap(recordBitmap, + DensityUtils.dip2px(cxt, 20f), DensityUtils.dip2px(cxt, 20f)); + } + + @Override + protected void convert(ViewHolder vh, final Tweet item, int position) { + vh.setImageForNet(R.id.iv_tweet_face, item.getAuthor().getPortrait(), R.mipmap.widget_dface); + CircleImageView iv_tweet_face = vh.getView(R.id.iv_tweet_face); + iv_tweet_face.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + OtherUserHomeActivity.show(mCallback.getContext(), item.getAuthor()); + } + }); + + vh.setText(R.id.tv_tweet_name, item.getAuthor().getName()); + vh.setText(R.id.tv_tweet_time, StringUtils.formatSomeAgo(item.getPubDate())); + PlatfromUtil.setPlatFromString((TextView) vh.getView(R.id.tv_tweet_platform), item.getAppClient()); + vh.setText(R.id.tv_tweet_like_count, String.valueOf(item.getLikeCount())); + vh.setText(R.id.tv_tweet_comment_count, String.valueOf(item.getCommentCount())); + + TweetTextView tv_content = vh.getView(R.id.tweet_item); + + String content = ""; + if (!TextUtils.isEmpty(item.getContent())) { + content = item.getContent().replaceAll("[\n\\s]+", " "); + } + Spannable spannable = AssimilateUtils.assimilateOnlyAtUser(mCallback.getContext(), content); + spannable = AssimilateUtils.assimilateOnlyTag(mCallback.getContext(), spannable); + spannable = AssimilateUtils.assimilateOnlyLink(mCallback.getContext(), spannable); + spannable = InputHelper.displayEmoji(mCallback.getContext().getResources(), spannable); + tv_content.setText(spannable); + tv_content.setMovementMethod(LinkMovementMethod.getInstance()); + tv_content.setFocusable(false); + tv_content.setDispatchToParent(true); + tv_content.setLongClickable(false); + + if (item.getAudio() != null) { + if (recordBitmap == null) { + initRecordImg(mCallback.getContext()); + } + ImageSpan recordImg = new ImageSpan(mCallback.getContext(), recordBitmap); + SpannableString str = new SpannableString("c"); + str.setSpan(recordImg, 0, 1, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); + tv_content.setText(str); + tv_content.append(spannable); + } else { + tv_content.setText(spannable); + } + + ImageView iv_tweet_like = vh.getView(R.id.iv_like_state); + iv_tweet_like.setImageResource(item.isLiked() ? R.mipmap.ic_thumbup_actived : R.mipmap.ic_thumb_normal); + iv_tweet_like.setTag(position); + iv_tweet_like.setOnClickListener(listener); + + Tweet.Image[] images = item.getImages(); + TweetPicturesLayout flowLayout = vh.getView(R.id.fl_image); + flowLayout.setImage(images); + } + + @Override + protected int getLayoutId(int position, Tweet item) { + return R.layout.item_list_tweet_improve; + } + + private abstract class OnTweetLikeClickListener implements View.OnClickListener { + @Override + public void onClick(View v) { + onClick(v, Integer.parseInt(v.getTag().toString())); + } + + public abstract void onClick(View v, int position); + } + + //点赞回调 + private class TweetLikedHandler extends TextHttpResponseHandler { + private int position; + + public TweetLikedHandler(int position) { + this.position = position; + } + + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + Type type = new TypeToken>() { + }.getType(); + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, type); + Tweet tweet = getItem(position); + tweet.setLiked(resultBean.getResult().isLiked()); + tweet.setLikeCount(resultBean.getResult().getLikeCount()); + updateItem(position, tweet); + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/tweet/adapter/TweetCommentAdapter.java b/app/src/main/java/net/oschina/app/improve/tweet/adapter/TweetCommentAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..4bd7d845089f5f5c28277e52f157c10d8796d70a --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/tweet/adapter/TweetCommentAdapter.java @@ -0,0 +1,99 @@ +package net.oschina.app.improve.tweet.adapter; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.RequestManager; + +import net.oschina.app.R; +import net.oschina.app.emoji.InputHelper; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.bean.simple.TweetComment; +import net.oschina.app.util.StringUtils; +import net.oschina.app.util.UIHelper; +import net.oschina.app.widget.TweetTextView; + +import butterknife.Bind; +import butterknife.ButterKnife; +import de.hdodenhof.circleimageview.CircleImageView; + +/** + * Created by thanatos + * on 16/6/13. + */ +public class TweetCommentAdapter extends BaseRecyclerAdapter { + + private RequestManager reqManager; + private View.OnClickListener onPortraitClickListener; + + public TweetCommentAdapter(Context context) { + super(context, ONLY_FOOTER); + reqManager = Glide.with(context); + } + + @Override + protected RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type) { + return new TweetCommentHolderView(LayoutInflater.from(mContext).inflate(R.layout.list_item_tweet_comment, parent, false)); + } + + @Override + protected void onBindDefaultViewHolder(RecyclerView.ViewHolder holder, TweetComment item, int position) { + TweetCommentHolderView h = (TweetCommentHolderView) holder; + h.ivPortrait.setTag(null); + if (TextUtils.isEmpty(item.getAuthor().getPortrait())) { + h.ivPortrait.setImageResource(R.mipmap.widget_dface); + } else { + reqManager + .load(item.getAuthor().getPortrait()) + .asBitmap() + .placeholder(mContext.getResources().getDrawable(R.mipmap.widget_dface)) + .error(mContext.getResources().getDrawable(R.mipmap.widget_dface)) + .into(h.ivPortrait); + } + h.ivPortrait.setTag(item); + h.ivPortrait.setOnClickListener(getOnPortraitClickListener()); + + h.tvName.setText(item.getAuthor().getName()); + h.tvContent.setText(InputHelper.displayEmoji(mContext.getResources(), item.getContent())); + h.tvTime.setText(StringUtils.formatSomeAgo(item.getPubDate())); + } + + private View.OnClickListener getOnPortraitClickListener() { + if (onPortraitClickListener == null) { + onPortraitClickListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + TweetComment comment = (TweetComment) v.getTag(); + UIHelper.showUserCenter(mContext, comment.getAuthor().getId(), comment.getAuthor().getName()); + } + }; + } + return onPortraitClickListener; + } + + public static final class TweetCommentHolderView extends RecyclerView.ViewHolder { + @Bind(R.id.iv_avatar) + public CircleImageView ivPortrait; + @Bind(R.id.tv_name) + public TextView tvName; + @Bind(R.id.tv_pub_date) + public TextView tvTime; + @Bind(R.id.btn_comment) + public ImageView btnReply; + @Bind(R.id.tv_content) + public TweetTextView tvContent; + + public TweetCommentHolderView(View view) { + super(view); + ButterKnife.bind(this, view); + } + } + +} diff --git a/app/src/main/java/net/oschina/app/improve/tweet/adapter/TweetLikeUsersAdapter.java b/app/src/main/java/net/oschina/app/improve/tweet/adapter/TweetLikeUsersAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..248b3e8ef7bb18bfef6b914b9dfcad11ef187981 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/tweet/adapter/TweetLikeUsersAdapter.java @@ -0,0 +1,84 @@ +package net.oschina.app.improve.tweet.adapter; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.RequestManager; + +import net.oschina.app.R; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.bean.simple.TweetLike; +import net.oschina.app.util.UIHelper; + +import butterknife.Bind; +import butterknife.ButterKnife; +import de.hdodenhof.circleimageview.CircleImageView; + +/** + * Created by thanatos on 16/6/13. + */ +public class TweetLikeUsersAdapter extends BaseRecyclerAdapter { + + private RequestManager reqManager; + private View.OnClickListener onPortraitClickListener; + + public TweetLikeUsersAdapter(Context context) { + super(context, ONLY_FOOTER); + reqManager = Glide.with(context); + } + + @Override + protected RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type) { + return new LikeUsersHolderView(LayoutInflater.from(mContext).inflate(R.layout.list_cell_tweet_like_user, parent, false)); + } + + @Override + protected void onBindDefaultViewHolder(RecyclerView.ViewHolder holder, TweetLike item, int position) { + LikeUsersHolderView h = (LikeUsersHolderView) holder; + h.ivPortrait.setTag(null); + if (TextUtils.isEmpty(item.getAuthor().getPortrait())) { + h.ivPortrait.setImageResource(R.mipmap.widget_dface); + } else { + reqManager.load(item.getAuthor().getPortrait()) + .asBitmap() + .placeholder(mContext.getResources().getDrawable(R.mipmap.widget_dface)) + .error(mContext.getResources().getDrawable(R.mipmap.widget_dface)) + .into(h.ivPortrait); + } + h.ivPortrait.setTag(item); + h.ivPortrait.setOnClickListener(getOnPortraitClickListener()); + h.tvName.setText(item.getAuthor().getName()); + } + + private View.OnClickListener getOnPortraitClickListener() { + if (onPortraitClickListener == null) { + onPortraitClickListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + TweetLike liker = (TweetLike) v.getTag(); + UIHelper.showUserCenter(mContext, liker.getAuthor().getId(), liker.getAuthor().getName()); + } + }; + } + return onPortraitClickListener; + } + + public static final class LikeUsersHolderView extends RecyclerView.ViewHolder { + @Bind(R.id.iv_avatar) + CircleImageView ivPortrait; + @Bind(R.id.tv_name) + TextView tvName; + + public LikeUsersHolderView(View view) { + super(view); + ButterKnife.bind(this, view); + } + } + +} diff --git a/app/src/main/java/net/oschina/app/improve/tweet/adapter/TweetQueueAdapter.java b/app/src/main/java/net/oschina/app/improve/tweet/adapter/TweetQueueAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..0e5778a768a151df13175cb39686a0dbe23a764c --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/tweet/adapter/TweetQueueAdapter.java @@ -0,0 +1,182 @@ +package net.oschina.app.improve.tweet.adapter; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.text.Spannable; +import android.text.method.LinkMovementMethod; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.TextView; + +import com.bumptech.glide.RequestManager; + +import net.oschina.app.R; +import net.oschina.app.emoji.InputHelper; +import net.oschina.app.improve.tweet.service.TweetPublishModel; +import net.oschina.app.improve.utils.AssimilateUtils; +import net.oschina.app.util.HTMLUtil; +import net.oschina.app.util.TDevice; +import net.oschina.app.util.TLog; +import net.oschina.app.widget.TweetTextView; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * Created by JuQiu + * on 16/8/03. + */ +public class TweetQueueAdapter extends RecyclerView.Adapter { + private final List mModels = new ArrayList<>(); + private Callback mCallback; + private static DateFormat FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + public TweetQueueAdapter(Callback callback) { + mCallback = callback; + } + + @Override + public Holder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_list_tweet_queue, parent, false); + return new Holder(view, new Holder.HolderListener() { + @Override + public void onDelete(TweetPublishModel model) { + remove(model); + Callback callback = mCallback; + if (callback != null) { + callback.onClickDelete(model); + } + } + + @Override + public void onContinue(TweetPublishModel model) { + remove(model); + Callback callback = mCallback; + if (callback != null) { + callback.onClickContinue(model); + } + } + }); + } + + @Override + public void onBindViewHolder(final Holder holder, int position) { + holder.bind(position, mModels.get(position), mCallback.getImageLoader()); + } + + @Override + public int getItemCount() { + return mModels.size(); + } + + public void add(List models) { + TLog.e("TAG", models.size() + ""); + mModels.addAll(models); + notifyDataSetChanged(); + } + + public void remove(TweetPublishModel model) { + int pos = mModels.indexOf(model); + if (pos != -1) { + mModels.remove(pos); + notifyItemRemoved(pos); + } + } + + + public interface Callback { + RequestManager getImageLoader(); + + void onClickContinue(TweetPublishModel model); + + void onClickDelete(TweetPublishModel model); + } + + /** + * Holder + */ + static class Holder extends RecyclerView.ViewHolder implements View.OnLongClickListener { + private TweetTextView mTitle; + private TextView mDate; + private TextView mLog; + private Button mContinue; + private Button mDelete; + private HolderListener mListener; + + private Holder(final View itemView, HolderListener listener) { + super(itemView); + // Add long click + itemView.setOnLongClickListener(this); + + mListener = listener; + + mTitle = (TweetTextView) itemView.findViewById(R.id.tv_title); + mLog = (TextView) itemView.findViewById(R.id.tv_log); + mDate = (TextView) itemView.findViewById(R.id.tv_date); + mContinue = (Button) itemView.findViewById(R.id.btn_continue); + mDelete = (Button) itemView.findViewById(R.id.btn_delete); + + mDelete.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Object obj = Holder.this.itemView.getTag(); + final HolderListener holderListener = mListener; + if (holderListener != null && obj != null && obj instanceof TweetPublishModel) { + holderListener.onDelete((TweetPublishModel) obj); + } + } + }); + mContinue.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Object obj = Holder.this.itemView.getTag(); + final HolderListener holderListener = mListener; + if (holderListener != null && obj != null && obj instanceof TweetPublishModel) { + holderListener.onContinue((TweetPublishModel) obj); + } + } + }); + } + + public void bind(int position, TweetPublishModel model, RequestManager loader) { + itemView.setTag(model); + + Context context = itemView.getContext(); + + Spannable spannable = AssimilateUtils.assimilateOnlyAtUser(context, model.getContent()); + spannable = AssimilateUtils.assimilateOnlyTag(context, spannable); + spannable = AssimilateUtils.assimilateOnlyLink(context, spannable); + spannable = InputHelper.displayEmoji(context.getResources(), spannable); + mTitle.setText(spannable); + mTitle.setMovementMethod(LinkMovementMethod.getInstance()); + mTitle.setFocusable(false); + mTitle.setDispatchToParent(true); + mTitle.setLongClickable(false); + + mLog.setText(String.format("Error:%s.", + model.getErrorString() == null ? "null" : model.getErrorString())); + mDate.setText(FORMAT.format(new Date(model.getDate()))); + } + + @Override + public boolean onLongClick(View v) { + TDevice.copyTextToBoard(HTMLUtil.delHTMLTag(mTitle.getText().toString())); + return true; + } + + /** + * Holder 与Adapter之间的桥梁 + */ + interface HolderListener { + void onDelete(TweetPublishModel model); + + void onContinue(TweetPublishModel model); + } + } + +} diff --git a/app/src/main/java/net/oschina/app/improve/tweet/adapter/TweetSelectImageAdapter.java b/app/src/main/java/net/oschina/app/improve/tweet/adapter/TweetSelectImageAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..6b99ea780aacd07bdb3c12b1d32a2e5d310850cf --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/tweet/adapter/TweetSelectImageAdapter.java @@ -0,0 +1,302 @@ +package net.oschina.app.improve.tweet.adapter; + +import android.content.Context; +import android.os.Vibrator; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.RequestManager; + +import net.oschina.app.R; +import net.oschina.app.improve.media.ImageGalleryActivity; +import net.oschina.app.improve.tweet.widget.TweetPicturesPreviewerItemTouchCallback; +import net.oschina.common.utils.CollectionUtil; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by JuQiu + * on 16/7/15. + */ +public class TweetSelectImageAdapter extends RecyclerView.Adapter implements TweetPicturesPreviewerItemTouchCallback.ItemTouchHelperAdapter { + private final int MAX_SIZE = 9; + private final int TYPE_NONE = 0; + private final int TYPE_ADD = 1; + private final List mModels = new ArrayList<>(); + private Callback mCallback; + + public TweetSelectImageAdapter(Callback callback) { + mCallback = callback; + } + + @Override + public int getItemViewType(int position) { + int size = mModels.size(); + if (size >= MAX_SIZE) + return TYPE_NONE; + else if (position == size) { + return TYPE_ADD; + } else { + return TYPE_NONE; + } + } + + @Override + public TweetSelectImageHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_list_tweet_publish_selecter, parent, false); + if (viewType == TYPE_NONE) { + return new TweetSelectImageHolder(view, new TweetSelectImageHolder.HolderListener() { + @Override + public void onDelete(Model model) { + Callback callback = mCallback; + if (callback != null) { + int pos = mModels.indexOf(model); + if (pos == -1) + return; + mModels.remove(pos); + if (mModels.size() > 0) + notifyItemRemoved(pos); + else + notifyDataSetChanged(); + } + } + + @Override + public void onDrag(TweetSelectImageHolder holder) { + Callback callback = mCallback; + if (callback != null) { + // Start a drag whenever the handle view it touched + mCallback.onStartDrag(holder); + } + } + + @Override + public void onClick(Model model) { + ImageGalleryActivity.show(mCallback.getContext(), model.path, false); + } + }); + } else { + return new TweetSelectImageHolder(view, new View.OnClickListener() { + @Override + public void onClick(View v) { + Callback callback = mCallback; + if (callback != null) { + callback.onLoadMoreClick(); + } + } + }); + } + } + + @Override + public void onBindViewHolder(final TweetSelectImageHolder holder, int position) { + int size = mModels.size(); + if (size >= MAX_SIZE || size != position) { + Model model = mModels.get(position); + holder.bind(position, model, mCallback.getImgLoader()); + } + } + + @Override + public void onViewRecycled(TweetSelectImageHolder holder) { + Glide.clear(holder.mImage); + } + + @Override + public int getItemCount() { + int size = mModels.size(); + if (size == MAX_SIZE) { + return size; + } else if (size == 0) { + return 0; + } else { + return size + 1; + } + } + + public void clear() { + mModels.clear(); + } + + public void add(Model model) { + if (mModels.size() >= MAX_SIZE) + return; + mModels.add(model); + } + + public void add(String path) { + add(new Model(path)); + } + + public String[] getPaths() { + int size = mModels.size(); + if (size == 0) + return null; + String[] paths = new String[size]; + int i = 0; + for (Model model : mModels) { + paths[i++] = model.path; + } + return paths; + } + + @Override + public boolean onItemMove(int fromPosition, int toPosition) { + //Collections.swap(mModels, fromPosition, toPosition); + if (fromPosition == toPosition) + return false; + + // Move fromPosition to toPosition + CollectionUtil.move(mModels, fromPosition, toPosition); + + notifyItemMoved(fromPosition, toPosition); + return true; + } + + @Override + public void onItemDismiss(int position) { + mModels.remove(position); + notifyItemRemoved(position); + } + + public static class Model { + public Model(String path) { + this.path = path; + } + + public String path; + public boolean isUpload; + } + + public interface Callback { + void onLoadMoreClick(); + + RequestManager getImgLoader(); + + Context getContext(); + + /** + * Called when a view is requesting a start of a drag. + * + * @param viewHolder The holder of the view to drag. + */ + void onStartDrag(RecyclerView.ViewHolder viewHolder); + } + + /** + * TweetSelectImageHolder + */ + static class TweetSelectImageHolder extends RecyclerView.ViewHolder implements TweetPicturesPreviewerItemTouchCallback.ItemTouchHelperViewHolder { + private ImageView mImage; + private ImageView mDelete; + private ImageView mGifMask; + private HolderListener mListener; + + private TweetSelectImageHolder(View itemView, HolderListener listener) { + super(itemView); + mListener = listener; + mImage = (ImageView) itemView.findViewById(R.id.iv_content); + mDelete = (ImageView) itemView.findViewById(R.id.iv_delete); + mGifMask = (ImageView) itemView.findViewById(R.id.iv_is_gif); + + mDelete.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Object obj = v.getTag(); + final HolderListener holderListener = mListener; + if (holderListener != null && obj != null && obj instanceof TweetSelectImageAdapter.Model) { + holderListener.onDelete((TweetSelectImageAdapter.Model) obj); + } + } + }); + mImage.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + final HolderListener holderListener = mListener; + if (holderListener != null) { + holderListener.onDrag(TweetSelectImageHolder.this); + } + return true; + } + }); + mImage.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Object obj = mDelete.getTag(); + final HolderListener holderListener = mListener; + if (holderListener != null && obj != null && obj instanceof TweetSelectImageAdapter.Model) { + holderListener.onClick((TweetSelectImageAdapter.Model) obj); + } + } + }); + mImage.setBackgroundColor(0xffdadada); + } + + private TweetSelectImageHolder(View itemView, View.OnClickListener clickListener) { + super(itemView); + + mImage = (ImageView) itemView.findViewById(R.id.iv_content); + mDelete = (ImageView) itemView.findViewById(R.id.iv_delete); + + mDelete.setVisibility(View.GONE); + mImage.setImageResource(R.mipmap.ic_tweet_add); + mImage.setOnClickListener(clickListener); + mImage.setBackgroundDrawable(null); + } + + public void bind(int position, TweetSelectImageAdapter.Model model, RequestManager loader) { + mDelete.setTag(model); + // In this we need clear before load + Glide.clear(mImage); + // Load image + if (model.path.toLowerCase().endsWith("gif")) { + loader.load(model.path) + .asBitmap() + .centerCrop() + .error(R.mipmap.ic_split_graph) + .into(mImage); + // Show gif mask + mGifMask.setVisibility(View.VISIBLE); + } else { + loader.load(model.path) + .centerCrop() + .error(R.mipmap.ic_split_graph) + .into(mImage); + mGifMask.setVisibility(View.GONE); + } + } + + + @Override + public void onItemSelected() { + try { + Vibrator vibrator = (Vibrator) itemView.getContext().getSystemService(Context.VIBRATOR_SERVICE); + vibrator.vibrate(20); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void onItemClear() { + + } + + /** + * Holder 与Adapter之间的桥梁 + */ + interface HolderListener { + void onDelete(TweetSelectImageAdapter.Model model); + + void onDrag(TweetSelectImageHolder holder); + + void onClick(TweetSelectImageAdapter.Model model); + } + } + +} diff --git a/app/src/main/java/net/oschina/app/improve/tweet/contract/TweetDetailContract.java b/app/src/main/java/net/oschina/app/improve/tweet/contract/TweetDetailContract.java new file mode 100644 index 0000000000000000000000000000000000000000..61d1e1c25dad2993c40e8337caf9bef9171db080 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/tweet/contract/TweetDetailContract.java @@ -0,0 +1,37 @@ +package net.oschina.app.improve.tweet.contract; + +import net.oschina.app.bean.User; +import net.oschina.app.improve.bean.Tweet; +import net.oschina.app.improve.bean.simple.TweetComment; + +/** + * Created by thanatosx + * on 16/5/28. + */ + +public interface TweetDetailContract { + + interface Operator { + + Tweet getTweetDetail(); + + void toReply(TweetComment comment); + + void onScroll(); + } + + interface ICmnView { + void onCommentSuccess(TweetComment comment); + } + + interface IThumbupView { + void onLikeSuccess(boolean isUp, User user); + } + + interface IAgencyView { + void resetLikeCount(int count); + + void resetCmnCount(int count); + } + +} diff --git a/app/src/main/java/net/oschina/app/improve/tweet/contract/TweetPublishContract.java b/app/src/main/java/net/oschina/app/improve/tweet/contract/TweetPublishContract.java new file mode 100644 index 0000000000000000000000000000000000000000..76bda531b200556c33df69e5f8b007d460bf9e2e --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/tweet/contract/TweetPublishContract.java @@ -0,0 +1,47 @@ +package net.oschina.app.improve.tweet.contract; + +import android.content.Context; +import android.os.Bundle; + +import net.oschina.app.improve.bean.simple.About; + +/** + * Created by JuQiu + * on 16/7/14. + */ + +public interface TweetPublishContract { + interface Operator { + void setDataView(View view, String defaultContent, String[] defaultImages, About.Share about); + + void publish(); + + void onBack(); + + void loadData(); + + void onSaveInstanceState(Bundle outState); + + void onRestoreInstanceState(Bundle savedInstanceState); + } + + interface View { + Context getContext(); + + String getContent(); + + void setContent(String content, boolean needSelectionEnd); + + void setAbout(About.Share about, boolean needCommit); + + boolean needCommit(); + + String[] getImages(); + + void setImages(String[] paths); + + void finish(); + + Operator getOperator(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/tweet/contract/TweetPublishOperator.java b/app/src/main/java/net/oschina/app/improve/tweet/contract/TweetPublishOperator.java new file mode 100644 index 0000000000000000000000000000000000000000..b44a55eaab71ac25721a0715053897688e43945e --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/tweet/contract/TweetPublishOperator.java @@ -0,0 +1,195 @@ +package net.oschina.app.improve.tweet.contract; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.support.v4.content.SharedPreferencesCompat; +import android.text.TextUtils; + +import net.oschina.app.AppContext; +import net.oschina.app.R; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.bean.simple.About; +import net.oschina.app.improve.tweet.fragments.TweetPublishFragment; +import net.oschina.app.improve.tweet.service.TweetPublishService; +import net.oschina.app.util.TDevice; +import net.oschina.app.util.UIHelper; +import net.oschina.common.utils.CollectionUtil; + +import java.util.List; +import java.util.Set; + +/** + * Created by JuQiu + * on 16/8/22. + */ +public class TweetPublishOperator implements TweetPublishContract.Operator { + private final static String SHARE_FILE_NAME = TweetPublishFragment.class.getName(); + private final static String SHARE_VALUES_CONTENT = "content"; + private final static String SHARE_VALUES_IMAGES = "images"; + private final static String SHARE_VALUES_ABOUT = "about"; + private final static String DEFAULT_PRE = "default"; + private TweetPublishContract.View mView; + private String mDefaultContent; + private String[] mDefaultImages; + private About.Share mAboutShare; + + @Override + public void setDataView(TweetPublishContract.View view, String defaultContent, String[] defaultImages, About.Share share) { + mView = view; + mDefaultContent = defaultContent; + mDefaultImages = defaultImages; + mAboutShare = share; + } + + @Override + public void publish() { + final Context context = mView.getContext(); + + if (!TDevice.hasInternet()) { + AppContext.showToastShort(R.string.tip_network_error); + return; + } + if (!AccountHelper.isLogin()) { + UIHelper.showLoginActivity(context); + return; + } + + String content = mView.getContent(); + if (TextUtils.isEmpty(content) || TextUtils.isEmpty(content.trim())) { + AppContext.showToastShort(R.string.tip_content_empty); + return; + } + + if (content.length() > TweetPublishFragment.MAX_TEXT_LENGTH) { + AppContext.showToastShort(R.string.tip_content_too_long); + return; + } + + // Check con't commit to tweet + if (About.check(mAboutShare) && mAboutShare.commitTweetId > 0 && !mView.needCommit()) { + mAboutShare.commitTweetId = 0; + } + + + final List paths = CollectionUtil.toArrayList(mView.getImages()); + + // To service publish + content = content.replaceAll("[\n\\s]+", " "); + TweetPublishService.startActionPublish(context, content, paths, mAboutShare); + + // Toast + AppContext.showToast(R.string.tweet_publishing_toast); + + // clear the tweet data + clearAndFinish(context); + } + + @Override + public void onBack() { + saveXmlData(); + mView.finish(); + } + + @Override + public void loadData() { + if (isUseXmlCache()) { + final Context context = mView.getContext(); + SharedPreferences sharedPreferences = context.getSharedPreferences(SHARE_FILE_NAME, Activity.MODE_PRIVATE); + String content = sharedPreferences.getString(SHARE_VALUES_CONTENT, null); + Set set = sharedPreferences.getStringSet(SHARE_VALUES_IMAGES, null); + if (content != null) { + mView.setContent(content, false); + } + if (set != null && set.size() > 0) { + mView.setImages(CollectionUtil.toArray(set, String.class)); + } + } else { + if (mDefaultImages != null && mDefaultImages.length > 0) + mView.setImages(mDefaultImages); + + boolean haveAbout = false; + if (About.check(mAboutShare)) { + mView.setAbout(mAboutShare, mAboutShare.commitTweetId > 0); + haveAbout = true; + } + + if (!TextUtils.isEmpty(mDefaultContent)) + mView.setContent(mDefaultContent, !haveAbout); + } + } + + @Override + public void onSaveInstanceState(Bundle outState) { + final String content = mView.getContent(); + final String[] paths = mView.getImages(); + if (content != null) + outState.putString(SHARE_VALUES_CONTENT, content); + if (paths != null && paths.length > 0) + outState.putStringArray(SHARE_VALUES_IMAGES, paths); + // save default + if (mDefaultContent != null) { + outState.putString(DEFAULT_PRE + SHARE_VALUES_CONTENT, mDefaultContent); + } + if (mDefaultImages != null && mDefaultImages.length > 0) { + outState.putStringArray(DEFAULT_PRE + SHARE_VALUES_IMAGES, mDefaultImages); + } + if (About.check(mAboutShare)) { + outState.putSerializable(DEFAULT_PRE + SHARE_VALUES_ABOUT, mAboutShare); + } + } + + @Override + public void onRestoreInstanceState(Bundle savedInstanceState) { + String content = savedInstanceState.getString(SHARE_VALUES_CONTENT, null); + String[] images = savedInstanceState.getStringArray(SHARE_VALUES_IMAGES); + if (content != null) { + mView.setContent(content, false); + } + if (images != null && images.length > 0) { + mView.setImages(images); + } + // Read default + mDefaultContent = savedInstanceState.getString(DEFAULT_PRE + SHARE_VALUES_CONTENT, null); + mDefaultImages = savedInstanceState.getStringArray(DEFAULT_PRE + SHARE_VALUES_IMAGES); + mAboutShare = (About.Share) savedInstanceState.getSerializable(DEFAULT_PRE + SHARE_VALUES_ABOUT); + if (About.check(mAboutShare)) + mView.setAbout(mAboutShare, mAboutShare.commitTweetId > 0); + } + + private void clearAndFinish(Context context) { + if (isUseXmlCache()) { + SharedPreferences sharedPreferences = context.getSharedPreferences(SHARE_FILE_NAME, Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putString(SHARE_VALUES_CONTENT, null); + editor.putStringSet(SHARE_VALUES_IMAGES, null); + SharedPreferencesCompat.EditorCompat.getInstance().apply(editor); + } + mView.finish(); + } + + + private void saveXmlData() { + if (isUseXmlCache()) { + final Context context = mView.getContext(); + final String content = mView.getContent(); + final String[] paths = mView.getImages(); + SharedPreferences sharedPreferences = context.getSharedPreferences(SHARE_FILE_NAME, Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putString(SHARE_VALUES_CONTENT, content); + if (paths != null && paths.length > 0) { + editor.putStringSet(SHARE_VALUES_IMAGES, CollectionUtil.toHashSet(paths)); + } else { + editor.putStringSet(SHARE_VALUES_IMAGES, null); + } + SharedPreferencesCompat.EditorCompat.getInstance().apply(editor); + } + } + + private boolean isUseXmlCache() { + return TextUtils.isEmpty(mDefaultContent) + && (mDefaultImages == null || mDefaultImages.length == 0) + && (!About.check(mAboutShare)); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/tweet/fragments/ListTweetCommentFragment.java b/app/src/main/java/net/oschina/app/improve/tweet/fragments/ListTweetCommentFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..91955eabc35f5ed3a4bfb02f653a04010928a1f5 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/tweet/fragments/ListTweetCommentFragment.java @@ -0,0 +1,183 @@ +package net.oschina.app.improve.tweet.fragments; + +import android.app.Activity; +import android.app.Dialog; +import android.content.DialogInterface; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.widget.Toast; + +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.base.fragments.BaseRecyclerViewFragment; +import net.oschina.app.improve.bean.base.PageBean; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.bean.simple.TweetComment; +import net.oschina.app.improve.tweet.adapter.TweetCommentAdapter; +import net.oschina.app.improve.tweet.contract.TweetDetailContract; +import net.oschina.app.improve.utils.DialogHelper; +import net.oschina.app.util.HTMLUtil; +import net.oschina.app.util.TDevice; +import net.oschina.app.util.UIHelper; + +import java.lang.reflect.Type; + +import cz.msebera.android.httpclient.Header; + +/** + * Created by thanatos + * on 16/6/13. + */ +public class ListTweetCommentFragment extends BaseRecyclerViewFragment + implements TweetDetailContract.ICmnView, BaseRecyclerAdapter.OnItemLongClickListener { + + private TweetDetailContract.Operator mOperator; + private TweetDetailContract.IAgencyView mAgencyView; + private int mDeleteIndex = 0; + private Dialog mDeleteDialog; + + public static ListTweetCommentFragment instantiate(TweetDetailContract.Operator operator, TweetDetailContract.IAgencyView mAgencyView) { + ListTweetCommentFragment fragment = new ListTweetCommentFragment(); + fragment.mOperator = operator; + fragment.mAgencyView = mAgencyView; + return fragment; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + mOperator = (TweetDetailContract.Operator) activity; + } + + @Override + protected void initWidget(View root) { + super.initWidget(root); + mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + super.onScrollStateChanged(recyclerView, newState); + if (newState == RecyclerView.SCROLL_STATE_DRAGGING) { + mOperator.onScroll(); + } + } + }); + } + + @Override + protected BaseRecyclerAdapter getRecyclerAdapter() { + TweetCommentAdapter adapter = new TweetCommentAdapter(getContext()); + adapter.setOnItemClickListener(this); + adapter.setOnItemLongClickListener(this); + return adapter; + } + + @Override + protected Type getType() { + return new TypeToken>>() { + }.getType(); + } + + @Override + protected void onRequestSuccess(int code) { + super.onRequestSuccess(code); + if (mAdapter.getCount() < 20 && mAgencyView != null) + mAgencyView.resetCmnCount(mAdapter.getCount()); + } + + @Override + public void requestData() { + String token = isRefreshing ? null : mBean.getNextPageToken(); + OSChinaApi.getTweetCommentList(mOperator.getTweetDetail().getId(), token, mHandler); + } + + @Override + protected boolean isNeedCache() { + return false; + } + + @Override + protected boolean isNeedEmptyView() { + return false; + } + + @Override + public void onItemClick(int position, long itemId) { + super.onItemClick(position, itemId); + TweetComment item = mAdapter.getItem(position); + if (item != null) + mOperator.toReply(item); + } + + @Override + public void onLongClick(int position, long itemId) { + final TweetComment comment = mAdapter.getItem(position); + if (comment == null) return; + int itemsLen = comment.getAuthor().getId() == AccountHelper.getUserId() ? 2 : 1; + String[] items = new String[itemsLen]; + items[0] = getResources().getString(R.string.copy); + if (itemsLen == 2) { + items[1] = getResources().getString(R.string.delete); + } + mDeleteIndex = position; + DialogHelper.getSelectDialog(getActivity(), items, "取消", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + if (i == 0) { + TDevice.copyTextToBoard(HTMLUtil.delHTMLTag(comment.getContent())); + } else if (i == 1) { + handleDeleteComment(comment); + } + } + }).show(); + } + + private void handleDeleteComment(TweetComment comment) { + if (!AccountHelper.isLogin()) { + UIHelper.showLoginActivity(getActivity()); + return; + } + mDeleteDialog = DialogHelper.getProgressDialog(getContext(), "正在删除...", false); + OSChinaApi.deleteTweetComment(mOperator.getTweetDetail().getId(), comment.getId(), new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + Toast.makeText(getContext(), "删除失败", Toast.LENGTH_SHORT).show(); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + ResultBean result = AppOperator.createGson().fromJson( + responseString, new TypeToken() { + }.getType()); + if (result.isSuccess()) { + mAdapter.removeItem(mDeleteIndex); + int count = mOperator.getTweetDetail().getCommentCount() - 1; + mOperator.getTweetDetail().setCommentCount(count); // Bean就这样写的,我也不知道为什么!!!! + mAgencyView.resetCmnCount(count); + } else { + Toast.makeText(getContext(), "删除失败", Toast.LENGTH_SHORT).show(); + } + } + + @Override + public void onFinish() { + super.onFinish(); + if (mDeleteDialog != null) { + mDeleteDialog.dismiss(); + mDeleteDialog = null; + } + } + }); + } + + @Override + public void onCommentSuccess(TweetComment comment) { + onRefreshing(); + } + +} diff --git a/app/src/main/java/net/oschina/app/improve/tweet/fragments/ListTweetLikeUsersFragment.java b/app/src/main/java/net/oschina/app/improve/tweet/fragments/ListTweetLikeUsersFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..ad192293d70184a14700757cfa6d49ac9b575984 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/tweet/fragments/ListTweetLikeUsersFragment.java @@ -0,0 +1,105 @@ +package net.oschina.app.improve.tweet.fragments; + +import android.app.Activity; +import android.support.v7.widget.RecyclerView; +import android.view.View; + +import com.google.gson.reflect.TypeToken; + +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.bean.User; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.base.fragments.BaseRecyclerViewFragment; +import net.oschina.app.improve.bean.base.PageBean; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.bean.simple.TweetLike; +import net.oschina.app.improve.tweet.adapter.TweetLikeUsersAdapter; +import net.oschina.app.improve.tweet.contract.TweetDetailContract; +import net.oschina.app.util.UIHelper; + +import java.lang.reflect.Type; + +/** + * 动弹详情, 点赞列表 + * Created by thanatos + * on 16/6/13. + */ +public class ListTweetLikeUsersFragment extends BaseRecyclerViewFragment implements TweetDetailContract.IThumbupView { + + private TweetDetailContract.Operator mOperator; + private TweetDetailContract.IAgencyView mAgencyView; + + public static ListTweetLikeUsersFragment instantiate(TweetDetailContract.Operator operator, TweetDetailContract.IAgencyView mAgencyView) { + ListTweetLikeUsersFragment fragment = new ListTweetLikeUsersFragment(); + fragment.mOperator = operator; + fragment.mAgencyView = mAgencyView; + return fragment; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + mOperator = (TweetDetailContract.Operator) activity; + } + + @Override + protected void initWidget(View root) { + super.initWidget(root); + mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + super.onScrollStateChanged(recyclerView, newState); + if (newState == RecyclerView.SCROLL_STATE_DRAGGING) { + mOperator.onScroll(); + } + } + }); + } + + @Override + protected BaseRecyclerAdapter getRecyclerAdapter() { + return new TweetLikeUsersAdapter(getContext()); + } + + @Override + protected Type getType() { + return new TypeToken>>() { + }.getType(); + } + + @Override + protected boolean isNeedCache() { + return false; + } + + @Override + protected boolean isNeedEmptyView() { + return false; + } + + @Override + protected void requestData() { + String token = isRefreshing ? null : mBean.getNextPageToken(); + OSChinaApi.getTweetLikeList(mOperator.getTweetDetail().getId(), token, mHandler); + } + + @Override + protected void onRequestSuccess(int code) { + super.onRequestSuccess(code); + if (mAdapter.getCount() < 20 && mAgencyView != null) + mAgencyView.resetLikeCount(mAdapter.getCount()); + } + + @Override + public void onItemClick(int position, long itemId) { + super.onItemClick(position, itemId); + TweetLike liker = mAdapter.getItem(position); + if (liker == null) return; + UIHelper.showUserCenter(getContext(), liker.getAuthor().getId(), liker.getAuthor().getName()); + } + + @Override + public void onLikeSuccess(boolean isUp, User user) { + onRefreshing(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/tweet/fragments/TopicTweetFragment.java b/app/src/main/java/net/oschina/app/improve/tweet/fragments/TopicTweetFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..4f82dc522c877ace3b9f6edc97cf0c74c8df7e25 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/tweet/fragments/TopicTweetFragment.java @@ -0,0 +1,46 @@ +package net.oschina.app.improve.tweet.fragments; + +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.base.fragments.BaseGeneralRecyclerFragment; +import net.oschina.app.improve.tweet.adapter.TopicTweetAdapter; + +import java.lang.reflect.Type; + +/** + * Created by thanatosx on 2016/11/7. + */ + +public class TopicTweetFragment extends BaseGeneralRecyclerFragment { + + @Override + protected BaseRecyclerAdapter getRecyclerAdapter() { + return new TopicTweetAdapter(getContext()); + } + + @Override + protected Type getType() { + return null; + } + + @Override + public void initData() { + super.initData(); + mAdapter.setState(BaseRecyclerAdapter.STATE_LOAD_MORE, true); + mRefreshLayout.setRefreshing(false); + } + + @Override + protected boolean isNeedEmptyView() { + return false; + } + + @Override + public void onRefreshing() { + + } + + @Override + protected boolean isNeedCache() { + return false; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/tweet/fragments/TweetFragment.java b/app/src/main/java/net/oschina/app/improve/tweet/fragments/TweetFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..039e0acc37d9829aabb5a53474ee8fb2f10a539d --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/tweet/fragments/TweetFragment.java @@ -0,0 +1,443 @@ +package net.oschina.app.improve.tweet.fragments; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.content.LocalBroadcastManager; +import android.support.v7.app.AppCompatActivity; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.widget.Toast; + +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.bean.Constants; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.account.activity.LoginActivity; +import net.oschina.app.improve.account.base.AccountBaseActivity; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.base.adapter.BaseGeneralRecyclerAdapter; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.base.fragments.BaseGeneralRecyclerFragment; +import net.oschina.app.improve.bean.Tweet; +import net.oschina.app.improve.bean.base.PageBean; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.bean.simple.About; +import net.oschina.app.improve.tweet.activities.TweetDetailActivity; +import net.oschina.app.improve.tweet.activities.TweetPublishActivity; +import net.oschina.app.improve.user.adapter.UserTweetAdapter; +import net.oschina.app.improve.utils.AssimilateUtils; +import net.oschina.app.improve.utils.CacheManager; +import net.oschina.app.improve.utils.DialogHelper; +import net.oschina.app.improve.widget.SimplexToast; +import net.oschina.app.ui.empty.EmptyLayout; +import net.oschina.app.util.HTMLUtil; +import net.oschina.app.util.TDevice; + +import org.json.JSONObject; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; + +import cz.msebera.android.httpclient.Header; + +/** + * 动弹列表 + * Created by huanghaibin_dev + * Updated by thanatosx + * on 2016/7/18. + */ +public class TweetFragment extends BaseGeneralRecyclerFragment + implements BaseRecyclerAdapter.OnItemLongClickListener { + + public static final int CATALOG_NEW = 0X0001; + public static final int CATALOG_HOT = 0X0002; + public static final int CATALOG_MYSELF = 0X0003; + public static final int CATALOG_FRIENDS = 0X0004; + public static final int CATALOG_TAG = 0X0005; + public static final int CATALOG_SOMEONE = 0X0006; + + public static final String CACHE_NEW_TWEET = "cache_new_tweet"; + public static final String CACHE_HOT_TWEET = "cache_hot_tweet"; + public static final String CACHE_USER_TWEET = "cache_user_tweet"; + public static final String CACHE_USER_FRIEND = "cache_user_friend"; + public static final String CACHE_USER_TAG = "cache_user_tag"; + + public static final String BUNDLE_KEY_USER_ID = "BUNDLE_KEY_USER_ID"; + public static final String BUNDLE_KEY_TAG = "BUNDLE_KEY_LOGIN_USER_TAG"; + public static final String BUNDLE_KEY_REQUEST_CATALOG = "BUNDLE_KEY_REQUEST_CATALOG"; + + public int mReqCatalog;//请求类型 + public long mUserId; // login user or another user + public String tag; + private LoginReceiver mReceiver; + + public static Fragment instantiate(long uid) { + Bundle bundle = new Bundle(); + bundle.putLong(BUNDLE_KEY_USER_ID, uid); + bundle.putInt(BUNDLE_KEY_REQUEST_CATALOG, CATALOG_MYSELF); + Fragment fragment = new TweetFragment(); + fragment.setArguments(bundle); + return fragment; + } + + /** + * @param uid user id + * @param code 只是为了让方法指纹不一样而已,哈哈 + * @return {@link Fragment} + */ + public static Fragment instantiate(long uid, int code) { + Bundle bundle = new Bundle(); + bundle.putLong(BUNDLE_KEY_USER_ID, uid); + bundle.putInt(BUNDLE_KEY_REQUEST_CATALOG, CATALOG_SOMEONE); + Fragment fragment = new TweetFragment(); + fragment.setArguments(bundle); + return fragment; + } + + public static Fragment instantiate(String tag) { + Bundle bundle = new Bundle(); + bundle.putString(BUNDLE_KEY_TAG, tag); + bundle.putInt(BUNDLE_KEY_REQUEST_CATALOG, CATALOG_TAG); + Fragment fragment = new TweetFragment(); + fragment.setArguments(bundle); + return fragment; + } + + public static Fragment instantiate(int catalog) { + Bundle bundle = new Bundle(); + bundle.putInt(BUNDLE_KEY_REQUEST_CATALOG, catalog); + Fragment fragment = new TweetFragment(); + fragment.setArguments(bundle); + return fragment; + } + + @Override + protected void initBundle(Bundle bundle) { + super.initBundle(bundle); + mReqCatalog = bundle.getInt(BUNDLE_KEY_REQUEST_CATALOG, CATALOG_NEW); + switch (mReqCatalog) { + case CATALOG_FRIENDS: + case CATALOG_SOMEONE: + case CATALOG_MYSELF: + mUserId = bundle.getLong(BUNDLE_KEY_USER_ID, AccountHelper.getUserId()); + break; + case CATALOG_TAG: + tag = bundle.getString(BUNDLE_KEY_TAG); + setHasOptionsMenu(true); + break; + } + } + + /** + * fragment被销毁的时候重新调用,初始化保存的数据 + * + * @param bundle onSaveInstanceState + */ + @Override + protected void onRestartInstance(Bundle bundle) { + super.onRestartInstance(bundle); + mReqCatalog = bundle.getInt(BUNDLE_KEY_REQUEST_CATALOG, CATALOG_NEW); + mUserId = bundle.getLong(BUNDLE_KEY_USER_ID, AccountHelper.getUserId()); + } + + @Override + public void initData() { + switch (mReqCatalog) { + case CATALOG_NEW: + CACHE_NAME = CACHE_NEW_TWEET; + break; + case CATALOG_HOT: + CACHE_NAME = CACHE_HOT_TWEET; + break; + case CATALOG_MYSELF: + case CATALOG_FRIENDS: + CACHE_NAME = mReqCatalog == CATALOG_MYSELF ? CACHE_USER_TWEET : CACHE_USER_FRIEND; + if (mReceiver == null) { + mReceiver = new LoginReceiver(); + IntentFilter filter = new IntentFilter(); + filter.addAction(AccountBaseActivity.ACTION_ACCOUNT_FINISH_ALL); + filter.addAction(Constants.INTENT_ACTION_LOGOUT); + LocalBroadcastManager.getInstance(getContext()).registerReceiver(mReceiver, filter); + } + break; + default: + CACHE_NAME = null; + } + + super.initData(); + + mAdapter.setOnItemLongClickListener(this); + // 某用户的动弹 or 登录用户的好友动弹 + if (mUserId == 0 && mReqCatalog == CATALOG_MYSELF || + (!AccountHelper.isLogin() && mReqCatalog == CATALOG_FRIENDS)) { + mErrorLayout.setErrorType(EmptyLayout.NETWORK_ERROR); + mErrorLayout.setErrorMessage("未登录"); + } + } + + @Override + public void onLongClick(final int position, long itemId) { + final Tweet tweet = mAdapter.getItem(position); + if (tweet == null) return; + + List operators = new ArrayList<>(); + operators.add(getString(R.string.copy)); + if (AccountHelper.getUserId() == (int) tweet.getAuthor().getId()) { + operators.add(getString(R.string.delete)); + } + operators.add(getString(R.string.transmit)); + + final String[] os = new String[operators.size()]; + operators.toArray(os); + + DialogHelper.getSelectDialog(getContext(), os, getString(R.string.cancle), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int index) { + switch (index) { + case 0: + TDevice.copyTextToBoard(HTMLUtil.delHTMLTag(tweet.getContent())); + break; + case 1: + if (os.length != 2) { + DialogHelper.getConfirmDialog(getActivity(), "是否删除该动弹?", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + OSChinaApi.deleteTweet(tweet.getId(), new DeleteHandler(position)); + } + }).show(); + break; + } + case 2: + String content = null; + About.Share share; + if (tweet.getAbout() == null) { + share = About.buildShare(tweet.getId(), OSChinaApi.CATALOG_TWEET); + share.title = tweet.getAuthor().getName(); + share.content = tweet.getContent(); + } else { + share = About.buildShare(tweet.getAbout()); + content = "//@" + tweet.getAuthor().getName() + " :" + tweet.getContent(); + content = AssimilateUtils.clearHtmlTag(content).toString(); + } + share.commitTweetId = tweet.getId(); + share.fromTweetId = tweet.getId(); + TweetPublishActivity.show(getContext(), null, content, share); + break; + } + } + }).show(); + } + + private class LoginReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + if (AccountHelper.isLogin()) { + mUserId = AccountHelper.getUserId(); + mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING); + onRefreshing(); + } else { + mUserId = 0; + mErrorLayout.setErrorType(EmptyLayout.NETWORK_ERROR); + mErrorLayout.setErrorMessage("未登录"); + } + } + } + + @Override + protected void requestData() { + super.requestData(); + String pageToken = isRefreshing ? null : mBean.getNextPageToken(); + switch (mReqCatalog) { + case CATALOG_NEW: + OSChinaApi.getTweetList(null, null, 1, 1, pageToken, mHandler); + break; + case CATALOG_HOT: + OSChinaApi.getTweetList(null, null, 1, 2, pageToken, mHandler); + break; + case CATALOG_SOMEONE: + case CATALOG_MYSELF: + if (mUserId <= 0) break; + OSChinaApi.getTweetList(mUserId, null, null, 1, pageToken, mHandler); + break; + case CATALOG_FRIENDS: + OSChinaApi.getTweetList(null, null, 2, 1, pageToken, mHandler); + break; + case CATALOG_TAG: + OSChinaApi.getTweetList(null, tag, null, 1, pageToken, mHandler); + break; + } + } + + @Override + protected boolean isNeedEmptyView() { + return mReqCatalog != CATALOG_TAG && mReqCatalog != CATALOG_SOMEONE; + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + if (mReqCatalog == CATALOG_TAG) { + inflater.inflate(R.menu.pub_topic_menu, menu); + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.public_menu_send: + TweetPublishActivity.show(getContext(), null, "#" + tag + "#"); + break; + } + return super.onOptionsItemSelected(item); + } + + @SuppressWarnings("unchecked") + @Override + public void onItemClick(int position, long itemId) { + Tweet tweet = mAdapter.getItem(position); + if (tweet == null) return; + TweetDetailActivity.show(getContext(), tweet); + } + + /** + * 未登录时显示的图标,点击应该跳到的登录界面 + * + * @param v {@link View} + */ + @Override + public void onClick(View v) { + if ((mReqCatalog == CATALOG_MYSELF || mReqCatalog == CATALOG_FRIENDS) + && !AccountHelper.isLogin()) { + //UIHelper.showLoginActivity(getActivity()); + LoginActivity.show(this, 1); + } else { + super.onClick(v); + } + } + + @Override + protected BaseRecyclerAdapter getRecyclerAdapter() { + return new UserTweetAdapter(this, BaseRecyclerAdapter.ONLY_FOOTER); + } + + @Override + protected Type getType() { + return new TypeToken>>() { + }.getType(); + } + + @Override + protected Class getCacheClass() { + return Tweet.class; + } + + @Override + public void onSaveInstanceState(Bundle outState) { + outState.putInt(BUNDLE_KEY_REQUEST_CATALOG, mReqCatalog); + outState.putLong(BUNDLE_KEY_USER_ID, mUserId); + super.onSaveInstanceState(outState); + } + + @SuppressWarnings("unchecked") + @Override + protected void setListData(ResultBean> resultBean) { + mBean.setNextPageToken(resultBean.getResult().getNextPageToken()); + if (isRefreshing) { + //cache the time + mBean.setItems(resultBean.getResult().getItems()); + mAdapter.clear(); + // 主要是为了清理重复数据, stupid + ((BaseGeneralRecyclerAdapter) mAdapter).clearPreItems(); + ((BaseGeneralRecyclerAdapter) mAdapter).addItems(mBean.getItems()); + + mBean.setPrevPageToken(resultBean.getResult().getPrevPageToken()); + mRefreshLayout.setCanLoadMore(true); + if (isNeedCache()) { + AppOperator.runOnThread(new Runnable() { + @Override + public void run() { + CacheManager.saveToJson(getActivity(), CACHE_NAME, mBean.getItems()); + } + }); + } + } else { + ((BaseGeneralRecyclerAdapter) mAdapter).addItems(resultBean.getResult().getItems()); + } + + mAdapter.setState(resultBean.getResult().getItems() == null + || resultBean.getResult().getItems().size() < 20 + ? BaseRecyclerAdapter.STATE_NO_MORE + : BaseRecyclerAdapter.STATE_LOADING, true); + + if (mAdapter.getItems().size() > 0) { + mErrorLayout.setErrorType(EmptyLayout.HIDE_LAYOUT); + mRefreshLayout.setVisibility(View.VISIBLE); + mRecyclerView.setVisibility(View.VISIBLE); + } else { + mErrorLayout.setErrorType(isNeedEmptyView() ? EmptyLayout.NODATA : EmptyLayout.HIDE_LAYOUT); + } + } + + /** + * 注销广播 + */ + @Override + public void onDestroy() { + if (mReceiver != null) { + LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(mReceiver); + } + super.onDestroy(); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode == AppCompatActivity.RESULT_OK && requestCode == 1) { + mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING); + mUserId = AccountHelper.getUserId(); + onRefreshing(); + } + } + + class DeleteHandler extends TextHttpResponseHandler { + private int position; + + DeleteHandler(int position) { + this.position = position; + } + + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + SimplexToast.show(getContext(), "删除失败"); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + JSONObject jsonObject = new JSONObject(responseString); + if (jsonObject.optInt("code") == 1) { + mAdapter.removeItem(position); + Toast.makeText(getActivity(), "删除成功", Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(getActivity(), jsonObject.optString("message"), Toast.LENGTH_SHORT).show(); + } + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/tweet/fragments/TweetPublishFragment.java b/app/src/main/java/net/oschina/app/improve/tweet/fragments/TweetPublishFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..cc96108e3b0949d1ee2cb5d7065019c2e17c1f93 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/tweet/fragments/TweetPublishFragment.java @@ -0,0 +1,447 @@ +package net.oschina.app.improve.tweet.fragments; + + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.view.ViewCompat; +import android.text.Editable; +import android.text.Spannable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.TextView; + +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.emoji.EmojiKeyboardFragment; +import net.oschina.app.emoji.Emojicon; +import net.oschina.app.emoji.InputHelper; +import net.oschina.app.emoji.OnEmojiClickListener; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.base.activities.BaseBackActivity; +import net.oschina.app.improve.base.fragments.BaseFragment; +import net.oschina.app.improve.bean.simple.About; +import net.oschina.app.improve.tweet.contract.TweetPublishContract; +import net.oschina.app.improve.tweet.contract.TweetPublishOperator; +import net.oschina.app.improve.tweet.widget.ClipView; +import net.oschina.app.improve.tweet.widget.TweetPicturesPreviewer; +import net.oschina.app.improve.utils.AssimilateUtils; +import net.oschina.app.ui.SelectFriendsActivity; +import net.oschina.app.util.UIHelper; + +import butterknife.Bind; +import butterknife.OnClick; + +/** + * 发布动弹界面实现 + */ +@SuppressWarnings("WeakerAccess") +public class TweetPublishFragment extends BaseFragment implements View.OnClickListener, TweetPublishContract.View { + public static final int MAX_TEXT_LENGTH = 160; + private static final int SELECT_FRIENDS_REQUEST_CODE = 100; + private static final String TEXT_TAG = "#输入软件名#"; + + @Bind(R.id.edit_content) + EditText mEditContent; + + @Bind(R.id.recycler_images) + TweetPicturesPreviewer mLayImages; + + @Bind(R.id.txt_indicator) + TextView mIndicator; + + @Bind(R.id.icon_back) + View mIconBack; + + @Bind(R.id.icon_send) + View mIconSend; + + private TweetPublishContract.Operator mOperator; + private final EmojiKeyboardFragment mEmojiKeyboard = new EmojiKeyboardFragment(); + + public TweetPublishFragment() { + // Required empty public constructor + } + + @Override + public void onAttach(Context context) { + // init operator + this.mOperator = new TweetPublishOperator(); + String defaultContent = null; + String[] paths = null; + About.Share share = null; + Bundle bundle = getArguments(); + if (bundle != null) { + defaultContent = bundle.getString("defaultContent"); + paths = bundle.getStringArray("defaultImages"); + share = (About.Share) bundle.getSerializable("aboutShare"); + } + this.mOperator.setDataView(this, defaultContent, paths, share); + + super.onAttach(context); + } + + @Override + protected int getLayoutId() { + return R.layout.fragment_tweet_publish; + } + + @Override + protected void initWidget(View root) { + super.initWidget(root); + if (root instanceof ClipView) { + ClipView clipView = ((ClipView) root); + + if (mBundle != null) { + clipView.setup(mBundle.getIntArray("location"), mBundle.getIntArray("size")); + } else { + clipView.setup(null, null); + } + + clipView.post(new Runnable() { + @Override + public void run() { + if (mRoot instanceof ClipView) { + ((ClipView) mRoot).start(new Runnable() { + @Override + public void run() { + mEmojiKeyboard.showSoftKeyboard(mEditContent); + } + }); + } else { + mEmojiKeyboard.showSoftKeyboard(mEditContent); + } + } + }); + } + + // EmojiKeyboardFragment + getChildFragmentManager().beginTransaction() + .replace(R.id.lay_emoji_keyboard, mEmojiKeyboard) + .commit(); + mEmojiKeyboard.setOnEmojiClickListener(new OnEmojiClickListener() { + @Override + public void onEmojiClick(Emojicon v) { + InputHelper.input2OSC(mEditContent, v); + } + + @Override + public void onDeleteButtonClick(View v) { + InputHelper.backspace(mEditContent); + } + }); + + // set hide action + mLayImages.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + mEmojiKeyboard.hideAllKeyBoard(); + return false; + } + }); + + // add text change listener + mEditContent.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + } + + @Override + public void afterTextChanged(Editable s) { + final int len = s.length(); + final int surplusLen = MAX_TEXT_LENGTH - len; + // set the send icon state + setSendIconStatus(len > 0 && surplusLen >= 0, s.toString()); + // checkShare the indicator state + if (surplusLen > 10) { + // hide + if (mIndicator.getVisibility() != View.INVISIBLE) { + ViewCompat.animate(mIndicator) + .alpha(0) + .setDuration(200) + .withEndAction(new Runnable() { + @Override + public void run() { + mIndicator.setVisibility(View.INVISIBLE); + } + }) + .start(); + } + } else { + // show + if (mIndicator.getVisibility() != View.VISIBLE) { + ViewCompat.animate(mIndicator) + .alpha(1f) + .setDuration(200) + .withStartAction(new Runnable() { + @Override + public void run() { + mIndicator.setVisibility(View.VISIBLE); + } + }) + .start(); + } + + mIndicator.setText(String.valueOf(surplusLen)); + //noinspection deprecation + mIndicator.setTextColor(surplusLen >= 0 ? + getResources().getColor(R.color.tweet_indicator_text_color) : + getResources().getColor(R.color.tweet_indicator_text_color_error)); + } + } + }); + } + + private void setSendIconStatus(boolean haveContent, String content) { + if (haveContent) { + content = content.trim(); + haveContent = (!TextUtils.isEmpty(content)) + && (!TEXT_TAG.equals(content)); + } + mIconSend.setEnabled(haveContent); + } + + + @Override + protected void initData() { + super.initData(); + mOperator.loadData(); + } + + @OnClick({R.id.iv_picture, R.id.iv_mention, R.id.iv_tag, + R.id.iv_emoji, R.id.txt_indicator, R.id.icon_back, R.id.icon_send}) + @Override + public void onClick(View v) { + try { + switch (v.getId()) { + case R.id.iv_picture: + mEmojiKeyboard.hideAllKeyBoard(); + mLayImages.onLoadMoreClick(); + break; + case R.id.iv_mention: + mEmojiKeyboard.hideAllKeyBoard(); + toSelectFriends(); + break; + case R.id.iv_tag: + insertTrendSoftware(); + break; + case R.id.iv_emoji: + handleEmojiClick(v); + break; + case R.id.txt_indicator: + handleClearContentClick(); + break; + case R.id.icon_back: + mOperator.onBack(); + break; + case R.id.icon_send: + mOperator.publish(); + break; + + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void handleClearContentClick() { + mIndicator.setSelected(!mIndicator.isSelected()); + if (mIndicator.isSelected()) { + mIndicator.postDelayed(new Runnable() { + @Override + public void run() { + mIndicator.setSelected(false); + } + }, 1000); + } else { + mEditContent.setText(""); + } + } + + /** + * Emoji 表情点击 + * + * @param v View + */ + private void handleEmojiClick(View v) { + if (!mEmojiKeyboard.isShow()) { + mEmojiKeyboard.hideSoftKeyboard(); + v.postDelayed(new Runnable() { + @Override + public void run() { + try { + mEmojiKeyboard.showEmojiKeyBoard(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }, 280); + } else { + mEmojiKeyboard.hideEmojiKeyBoard(); + } + } + + /** + * 插入 #软件名# + */ + private void insertTrendSoftware() { + final EditText editText = mEditContent; + final int maxTextLen = MAX_TEXT_LENGTH; + int curTextLength = editText.getText().length(); + if (curTextLength >= maxTextLen) + return; + String software = TEXT_TAG; + int start, end; + if ((maxTextLen - curTextLength) >= software.length()) { + start = editText.getSelectionStart() + 1; + end = start + software.length() - 2; + } else { + int num = maxTextLen - curTextLength; + if (num < software.length()) { + software = software.substring(0, num); + } + start = editText.getSelectionStart() + 1; + end = start + software.length() - 1; + } + if (start > maxTextLen || end > maxTextLen) { + start = maxTextLen; + end = maxTextLen; + } + editText.getText().insert(editText.getSelectionStart(), software); + editText.setSelection(start, end); + } + + /** + * 跳转选择好友 + */ + private void toSelectFriends() { + Context context = getContext(); + if (context == null) + return; + if (!AccountHelper.isLogin()) { + UIHelper.showLoginActivity(context); + return; + } + Intent intent = new Intent(context, SelectFriendsActivity.class); + startActivityForResult(intent, SELECT_FRIENDS_REQUEST_CODE); + } + + /** + * 好友名字选择 + * + * @param data Intent + */ + private void handleSelectFriendsResult(Intent data) { + String names[] = data.getStringArrayExtra("names"); + if (names != null && names.length > 0) { + String text = ""; + for (String n : names) { + text += "@" + n + " "; + } + mEditContent.getText().insert(mEditContent.getSelectionStart(), text); + } + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode != Activity.RESULT_OK) + return; + if (requestCode == SELECT_FRIENDS_REQUEST_CODE) { + handleSelectFriendsResult(data); + } + } + + @Override + public String getContent() { + return mEditContent.getText().toString(); + } + + @Override + public void setContent(String content, boolean needSelectionEnd) { + Spannable span = InputHelper.displayEmoji(getResources(), content, (int) mEditContent.getTextSize()); + mEditContent.setText(span); + if (needSelectionEnd) + mEditContent.setSelection(mEditContent.getText().length()); + } + + @Override + public void setAbout(About.Share share, boolean needCommit) { + if (TextUtils.isEmpty(share.title) && TextUtils.isEmpty(share.content)) + return; + // Change the layout visibility + mLayImages.setVisibility(View.GONE); + setVisibility(R.id.lay_about); + // Set title and content + ((TextView) findView(R.id.txt_about_title)).setText(share.type == OSChinaApi.COMMENT_TWEET ? + "@" + share.title : share.title); + ((TextView) findView(R.id.txt_about_content)).setText(AssimilateUtils.clearHtmlTag(share.content)); + findView(R.id.iv_picture).setEnabled(false); + + if (needCommit) + setVisibility(R.id.cb_commit_control); + else + setGone(R.id.cb_commit_control); + } + + @Override + public boolean needCommit() { + return ((CheckBox) findView(R.id.cb_commit_control)).isChecked(); + } + + @Override + public String[] getImages() { + return mLayImages.getPaths(); + } + + @Override + public void setImages(String[] paths) { + mLayImages.set(paths); + } + + @Override + public void finish() { + // hide key board before finish + mEmojiKeyboard.hideAllKeyBoard(); + // do animation to finish + if (mRoot instanceof ClipView) { + ((ClipView) mRoot).exit(new Runnable() { + @Override + public void run() { + Activity activity = getActivity(); + if (activity != null && activity instanceof BaseBackActivity) { + ((BaseBackActivity) activity).onSupportNavigateUp(); + } + } + }); + } + } + + @Override + public TweetPublishContract.Operator getOperator() { + return mOperator; + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + mOperator.onSaveInstanceState(outState); + } + + @Override + public void onInflate(Context context, AttributeSet attrs, Bundle savedInstanceState) { + super.onInflate(context, attrs, savedInstanceState); + if (savedInstanceState != null) + mOperator.onRestoreInstanceState(savedInstanceState); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/tweet/fragments/TweetViewPagerFragment.java b/app/src/main/java/net/oschina/app/improve/tweet/fragments/TweetViewPagerFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..c3edc1e9df60a4da3ff89423d654cbff68aaa8cb --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/tweet/fragments/TweetViewPagerFragment.java @@ -0,0 +1,96 @@ +package net.oschina.app.improve.tweet.fragments; + +import android.os.Build; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import net.oschina.app.R; +import net.oschina.app.adapter.ViewPageFragmentAdapter; +import net.oschina.app.base.BaseViewPagerFragment; +import net.oschina.app.improve.base.fragments.BaseGeneralListFragment; +import net.oschina.app.improve.utils.UIUtil; +import net.oschina.app.interf.OnTabReselectListener; + + +/** + * 动弹ViewPagerFragment + * Created by huanghaibin_dev + * on 2016/7/19. + */ +public class TweetViewPagerFragment extends BaseViewPagerFragment implements + OnTabReselectListener { + + @Override + protected void onSetupTabAdapter(ViewPageFragmentAdapter adapter) { + + FrameLayout generalActionBar = (FrameLayout) mRoot.findViewById(R.id.general_actionbar); + TextView tvTitle = (TextView) generalActionBar.findViewById(R.id.tv_explore_scan); + ImageView ivDiscover = (ImageView) generalActionBar.findViewById(R.id.iv_explore_discover); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) generalActionBar.getLayoutParams(); + layoutParams.topMargin = UIUtil.getStatusHeight(getActivity()); + } + tvTitle.setText(R.string.main_tab_name_tweet); + ivDiscover.setVisibility(View.INVISIBLE); + + String[] title = getResources().getStringArray( + R.array.tweets_viewpage_arrays); + + adapter.addTab(title[0], "tweet_new", TweetFragment.class, + getBundle(TweetFragment.CATALOG_NEW)); + adapter.addTab(title[1], "tweet_hot", TweetFragment.class, + getBundle(TweetFragment.CATALOG_HOT)); + adapter.addTab(title[2], "tweet_mine", TweetFragment.class, + getBundle(TweetFragment.CATALOG_MYSELF)); + + } + + /** + * @param catalog {@link TweetFragment} + * @return Bundle + */ + private Bundle getBundle(int catalog) { + Bundle bundle = new Bundle(); + bundle.putInt(TweetFragment.BUNDLE_KEY_REQUEST_CATALOG, catalog); + return bundle; + } + + @Override + protected void setScreenPageLimit() { + mViewPager.setOffscreenPageLimit(3); + } + + + @Override + public void onClick(View v) { + + } + + @Override + public void initView(View view) { + FrameLayout actionBar = (FrameLayout) view.findViewById(R.id.general_actionbar); + TextView tvTweetTitle = (TextView) actionBar.findViewById(R.id.tv_explore_scan); + tvTweetTitle.setText(R.string.main_tab_name_tweet); + ImageView ivDiscover = (ImageView) actionBar.findViewById(R.id.iv_explore_discover); + ivDiscover.setVisibility(View.INVISIBLE); + + } + + @Override + public void initData() { + + } + + @Override + public void onTabReselect() { + Fragment fragment = mTabsAdapter.getItem(mViewPager.getCurrentItem()); + if (fragment != null && fragment instanceof BaseGeneralListFragment) { + ((BaseGeneralListFragment) fragment).onTabReselect(); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/oschina/app/improve/tweet/service/Contract.java b/app/src/main/java/net/oschina/app/improve/tweet/service/Contract.java new file mode 100644 index 0000000000000000000000000000000000000000..b74d5514b48e59dc97d5fcaa8bbc56ad1a461f04 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/tweet/service/Contract.java @@ -0,0 +1,26 @@ +package net.oschina.app.improve.tweet.service; + +/** + * Created by JuQiu + * on 16/7/21. + */ + +interface Contract { + interface IService { + String getCachePath(String id); + + void start(String modelId, IOperator operator); + + void stop(String id, int startId); + + void notifyMsg(int notifyId, String modelId, boolean haveReDo, boolean haveDelete, int resId, Object... values); + + void notifyCancel(int notifyId); + + void updateModelCache(String id, TweetPublishModel model); + } + + interface IOperator extends Runnable { + void stop(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/tweet/service/LopperResponseHandler.java b/app/src/main/java/net/oschina/app/improve/tweet/service/LopperResponseHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..2f51d99bdfa5c9bb68b1ff0e954da092e266da6c --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/tweet/service/LopperResponseHandler.java @@ -0,0 +1,85 @@ +package net.oschina.app.improve.tweet.service; + +import android.os.Looper; + +import com.loopj.android.http.AsyncHttpClient; +import com.loopj.android.http.AsyncHttpResponseHandler; + +import java.io.UnsupportedEncodingException; + +import cz.msebera.android.httpclient.Header; + +/** + * Created by JuQiu + * on 16/7/19. + */ +@SuppressWarnings("WeakerAccess") +public abstract class LopperResponseHandler extends AsyncHttpResponseHandler { + private static final String LOG_TAG = "TextHttpRH"; + + /** + * Creates new instance with default UTF-8 encoding + */ + public LopperResponseHandler() { + this(DEFAULT_CHARSET); + } + + /** + * Creates new instance with given string encoding + * + * @param encoding String encoding, see {@link #setCharset(String)} + */ + public LopperResponseHandler(String encoding) { + super(Looper.myLooper()); + setCharset(encoding); + } + + /** + * Attempts to encode response bytes as string of set encoding + * + * @param charset charset to create string with + * @param stringBytes response bytes + * @return String of set encoding or null + */ + public static String getResponseString(byte[] stringBytes, String charset) { + try { + String toReturn = (stringBytes == null) ? null : new String(stringBytes, charset); + if (toReturn != null && toReturn.startsWith(UTF8_BOM)) { + return toReturn.substring(1); + } + return toReturn; + } catch (UnsupportedEncodingException e) { + AsyncHttpClient.log.e(LOG_TAG, "Encoding response into string failed", e); + return null; + } + } + + /** + * Called when request fails + * + * @param statusCode http response status line + * @param headers response headers if any + * @param responseString string response of given charset + * @param throwable throwable returned when processing request + */ + public abstract void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable); + + /** + * Called when request succeeds + * + * @param statusCode http response status line + * @param headers response headers if any + * @param responseString string response of given charset + */ + public abstract void onSuccess(int statusCode, Header[] headers, String responseString); + + @Override + public void onSuccess(int statusCode, Header[] headers, byte[] responseBytes) { + onSuccess(statusCode, headers, getResponseString(responseBytes, getCharset())); + } + + @Override + public void onFailure(int statusCode, Header[] headers, byte[] responseBytes, Throwable throwable) { + onFailure(statusCode, headers, getResponseString(responseBytes, getCharset()), throwable); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/tweet/service/TweetPublishCache.java b/app/src/main/java/net/oschina/app/improve/tweet/service/TweetPublishCache.java new file mode 100644 index 0000000000000000000000000000000000000000..1dd0534ba36cbaa2ed8ca9ba08c1e7b31caf1593 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/tweet/service/TweetPublishCache.java @@ -0,0 +1,164 @@ +package net.oschina.app.improve.tweet.service; + +import android.content.Context; + +import net.oschina.app.util.TLog; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InvalidClassException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.ArrayList; +import java.util.List; + +import static net.oschina.common.utils.StreamUtil.close; + + +/** + * Created by JuQiu + * on 16/7/21. + */ +@SuppressWarnings("WeakerAccess") +public class TweetPublishCache { + private final static String TAG = TweetPublishCache.class.getName(); + + private TweetPublishCache() { + + } + + static String getImageCachePath(Context context, String id) { + return String.format("%s/TweetPictures/%s", context.getCacheDir().getAbsolutePath(), id); + } + + @SuppressWarnings("ResultOfMethodCallIgnored") + static String getFileCachePath(Context context, String id) { + String dir = context.getFilesDir().getAbsolutePath() + "/TweetQueue"; + File file = new File(dir); + if (!file.exists()) { + file.mkdirs(); + } + if (id != null) { + return String.format("%s/%s.tweet", dir, id); + } + return dir; + } + + static String getIdByFile(File file) { + if (file == null) + return null; + String name = file.getName(); + int index = name.indexOf(".tweet"); + if (index == -1) + return name; + return name.substring(0, index); + } + + static void removeImages(Context context, String id) { + String dir = getImageCachePath(context, id); + File file = new File(dir); + if (file.exists() && file.isDirectory()) { + deleteDir(file); + } + } + + public static boolean have(Context context, String id) { + File data = new File(getFileCachePath(context, id)); + return data.exists(); + } + + public static List list(Context context) { + File fileDir = new File(getFileCachePath(context, null)); + if (fileDir.exists() && fileDir.isDirectory()) { + File[] files = fileDir.listFiles(); + if (files != null && fileDir.length() > 0) { + List models = new ArrayList<>(); + for (File file : files) { + String id = getIdByFile(file); + TweetPublishModel model = get(context, id); + if (model != null) + models.add(model); + } + return models; + } + } + return null; + } + + @SuppressWarnings("ResultOfMethodCallIgnored") + public static boolean save(Context context, String id, TweetPublishModel model) { + final String path = getFileCachePath(context, id); + log("save", path); + FileOutputStream fos = null; + ObjectOutputStream oos = null; + try { + File file = new File(path); + if (file.exists()) + file.delete(); + file.createNewFile(); + fos = new FileOutputStream(path); + oos = new ObjectOutputStream(fos); + oos.writeObject(model); + oos.flush(); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } finally { + close(oos, fos); + } + } + + public static TweetPublishModel get(Context context, String id) { + if (!have(context, id)) + return null; + + final String path = getFileCachePath(context, id); + log("get", path); + FileInputStream fis = null; + ObjectInputStream ois = null; + try { + fis = new FileInputStream(path); + ois = new ObjectInputStream(fis); + return (TweetPublishModel) ois.readObject(); + } catch (FileNotFoundException ignored) { + } catch (InvalidClassException e) { + e.printStackTrace(); + remove(context, id); + } catch (IOException | ClassNotFoundException e) { + e.printStackTrace(); + } finally { + close(ois, fis); + } + return null; + } + + public static boolean remove(Context context, String id) { + // To clear the images cache + removeImages(context, id); + + File data = new File(getFileCachePath(context, id)); + log("remove", data.getAbsolutePath()); + return !data.exists() || data.delete(); + } + + + @SuppressWarnings("ResultOfMethodCallIgnored") + private static void deleteDir(File dir) { + if (dir.isDirectory()) { + String[] children = dir.list(); + for (String c : children) { + deleteDir(new File(dir, c)); + } + } + log("delete", dir.getAbsolutePath()); + dir.delete(); + } + + private static void log(String action, String msg) { + TLog.e(TAG, String.format("%s:%s", action, msg)); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/tweet/service/TweetPublishModel.java b/app/src/main/java/net/oschina/app/improve/tweet/service/TweetPublishModel.java new file mode 100644 index 0000000000000000000000000000000000000000..4083c23977f2f46ea91b88c588ccecb5aaa9fb11 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/tweet/service/TweetPublishModel.java @@ -0,0 +1,104 @@ +package net.oschina.app.improve.tweet.service; + +import net.oschina.app.improve.bean.simple.About; + +import java.io.Serializable; +import java.util.UUID; + +/** + * Created by JuQiu + * on 16/7/21. + */ + +@SuppressWarnings("WeakerAccess") +public class TweetPublishModel implements Serializable { + private String id; + private long date; + private String content; + private String[] srcImages; + private String[] cacheImages; + private String cacheImagesToken; + private int cacheImagesIndex; + private String errorString; + private long aboutId; + private int aboutType; + private long aboutCommitId; + private long aboutFromTweetId; + + public TweetPublishModel() { + id = UUID.randomUUID().toString(); + date = System.currentTimeMillis(); + } + + public TweetPublishModel(String content, String[] images, About.Share share) { + this(); + this.content = content; + this.srcImages = images; + if (About.check(share)) { + this.aboutId = share.id; + this.aboutType = share.type; + this.aboutCommitId = share.commitTweetId; + this.aboutFromTweetId = share.fromTweetId; + } + } + + public String getId() { + return id; + } + + public long getDate() { + return date; + } + + public void setDate(long date) { + this.date = date; + } + + public String getContent() { + return content; + } + + public About.Share getAboutShare() { + About.Share share = About.buildShare(aboutId, aboutType); + if (About.check(share)) { + share.commitTweetId = aboutCommitId; + share.fromTweetId = aboutFromTweetId; + return share; + } + return null; + } + + public String[] getSrcImages() { + return srcImages; + } + + public String[] getCacheImages() { + return cacheImages; + } + + public String getCacheImagesToken() { + return cacheImagesToken; + } + + public int getCacheImagesIndex() { + return cacheImagesIndex; + } + + public void setCacheImages(String[] cacheImages) { + this.cacheImages = cacheImages; + this.srcImages = null; + } + + public void setCacheImagesInfo(int cacheImagesIndex, String cacheImagesToken) { + this.cacheImagesToken = cacheImagesToken; + this.cacheImagesIndex = cacheImagesIndex; + } + + public String getErrorString() { + return errorString; + } + + public void setErrorString(String errorString) { + this.errorString = errorString; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/tweet/service/TweetPublishOperator.java b/app/src/main/java/net/oschina/app/improve/tweet/service/TweetPublishOperator.java new file mode 100644 index 0000000000000000000000000000000000000000..256bb6b5c9b1752af01098a6f59d5ff8e21e562b --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/tweet/service/TweetPublishOperator.java @@ -0,0 +1,330 @@ +package net.oschina.app.improve.tweet.service; + +import android.graphics.BitmapFactory; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.bean.resource.ImageResource; +import net.oschina.app.improve.bean.simple.About; +import net.oschina.app.improve.utils.PicturesCompressor; +import net.oschina.common.utils.BitmapUtil; + +import java.io.File; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; + +import cz.msebera.android.httpclient.Header; + +/** + * Created by JuQiu + * on 16/7/21. + * 动弹发布执行者 + */ +class TweetPublishOperator implements Runnable, Contract.IOperator { + private final int serviceStartId; + private final int notificationId; + private Contract.IService service; + private TweetPublishModel model; + + interface UploadImageCallback { + void onUploadImageDone(); + + void onUploadImage(int index, String token); + } + + TweetPublishOperator(TweetPublishModel model, Contract.IService service, int startId) { + this.model = model; + this.notificationId = model.getId().hashCode(); + this.serviceStartId = startId; + this.service = service; + } + + /** + * 执行动弹发布操作 + */ + @Override + public void run() { + // call to service + this.service.start(model.getId(), this); + // notify + notifyMsg(R.string.tweet_publishing); + + // doing + final TweetPublishModel model = this.model; + if (model.getSrcImages() == null && model.getCacheImages() == null) { + // 当没有图片的时候,直接进行发布动弹 + publish(); + } else { + if (model.getCacheImages() == null) { + notifyMsg(R.string.tweet_image_wait); + final String cacheDir = service.getCachePath(model.getId()); + // change the model + model.setCacheImages(saveImageToCache(cacheDir, model.getSrcImages())); + // update to cache file + service.updateModelCache(model.getId(), model); + + if (model.getCacheImages() == null) { + notifyMsg(R.string.tweet_image_wait_failed); + publish(); + return; + } + } + // 开始上传图片,并回调进度 + uploadImages(model.getCacheImagesIndex(), model.getCacheImagesToken(), model.getCacheImages(), + new UploadImageCallback() { + @Override + public void onUploadImageDone() { + publish(); + } + + @Override + public void onUploadImage(int index, String token) { + model.setCacheImagesInfo(index, token); + // update to cache file + service.updateModelCache(model.getId(), model); + } + }); + } + } + + /** + * 上传图片 + * + * @param index 上次图片的坐标 + * @param token 上传Token + * @param paths 上传的路径数组 + * @param runnable 完全上传完成时回调 + */ + private void uploadImages(final int index, final String token, final String[] paths, final UploadImageCallback runnable) { + // call progress + runnable.onUploadImage(index, token); + + // checkShare done + if (index < 0 || index >= paths.length) { + runnable.onUploadImageDone(); + return; + } + + final String path = paths[index]; + + OSChinaApi.uploadImage(token, path, new LopperResponseHandler() { + @Override + public void onStart() { + super.onStart(); + notifyMsg(R.string.tweet_image_publishing, String.valueOf(paths.length - index)); + } + + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + String error = ""; + String response = responseString == null ? "" : responseString; + if (throwable != null) { + throwable.printStackTrace(); + error = throwable.getMessage(); + if (error.contains("UnknownHostException") + || error.contains("Read error: ssl") + || error.contains("Connection timed out")) { + saveError("Upload", "network error"); + } else { + saveError("Upload", response + " " + error); + } + } + TweetPublishService.log(String.format("Upload image onFailure, statusCode:[%s] responseString:%s throwable:%s", + statusCode, response, error)); + setError(R.string.tweet_image_publish_failed, String.valueOf(index + 1), String.valueOf(paths.length)); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + Type type = new TypeToken>() { + }.getType(); + ResultBean resultBean = new Gson().fromJson(responseString, type); + if (resultBean.isSuccess()) { + String token = resultBean.getResult().getToken(); + uploadImages(index + 1, token, paths, runnable); + } else { + File file = new File(path); + TweetPublishService.log(String.format("Upload name:[%s] size:[%s] error:%s", + file.getAbsolutePath(), file.length(), resultBean.getMessage())); + saveError("Upload", resultBean.getMessage()); + onFailure(statusCode, headers, responseString, null); + } + } catch (Exception e) { + saveError("Upload", "response parse error「" + responseString + "」"); + onFailure(statusCode, headers, responseString, null); + } + } + }); + } + + @Override + public void stop() { + final Contract.IService service = this.service; + if (service != null) { + this.service = null; + service.stop(model.getId(), serviceStartId); + } + } + + /** + * 发布动弹 + */ + private void publish() { + OSChinaApi.pubTweet(model.getContent(), model.getCacheImagesToken(), null, model.getAboutShare(), new LopperResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + String error = ""; + String response = responseString == null ? "" : responseString; + if (throwable != null) { + throwable.printStackTrace(); + error = throwable.getMessage(); + if (error.contains("UnknownHostException") + || error.contains("Read error: ssl") + || error.contains("Connection timed out")) { + saveError("Publish", "network error"); + } else { + saveError("Publish", response + " " + error); + } + } + + TweetPublishService.log(String.format("Publish tweet onFailure, statusCode:[%s] responseString:%s throwable:%s", + statusCode, response, error)); + setError(R.string.tweet_publish_failed); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + Type type = new TypeToken() { + }.getType(); + ResultBean resultBean = new Gson().fromJson(responseString, type); + if (resultBean.isSuccess()) { + setSuccess(); + } else { + saveError("Publish", resultBean.getMessage()); + onFailure(statusCode, headers, responseString, null); + } + } catch (Exception e) { + saveError("Publish", "response parse error「" + responseString + "」"); + onFailure(statusCode, headers, responseString, null); + } + } + }); + } + + private void notifyMsg(int resId, Object... values) { + notifyMsg(false, resId, values); + } + + private void notifyMsg(boolean done, int resId, Object... values) { + Contract.IService service = this.service; + if (service != null) { + service.notifyMsg(notificationId, model.getId(), done, done, resId, values); + } + } + + private void setSuccess() { + notifyMsg(R.string.tweet_publish_success); + try { + Thread.sleep(1600); + } catch (InterruptedException e) { + e.printStackTrace(); + } + Contract.IService service = this.service; + if (service != null) { + // clear the cache + service.updateModelCache(model.getId(), null); + // hide the notify + service.notifyCancel(notificationId); + } + + // Check the about commit id + if (!checkToCommit()) + stop(); + } + + private void setError(int resId, Object... values) { + notifyMsg(true, resId, values); + stop(); + } + + private boolean checkToCommit() { + // 如果相关节点中定义了评论参数,那么将执行评论 + About.Share share = model.getAboutShare(); + if (About.check(share) && share.commitTweetId > 0) { + OSChinaApi.pubTweetComment(share.commitTweetId, model.getContent(), 0, new LopperResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + } + + @Override + public void onFinish() { + super.onFinish(); + stop(); + } + }); + return true; + } + return false; + } + + + // Max upload 860KB + private static final long MAX_UPLOAD_LENGTH = 860 * 1024; + + /** + * 保存文件到缓存中 + * + * @param cacheDir 缓存文件夹 + * @param paths 原始路径 + * @return 转存后的路径 + */ + private static String[] saveImageToCache(String cacheDir, String[] paths) { + List ret = new ArrayList<>(); + byte[] buffer = new byte[BitmapUtil.DEFAULT_BUFFER_SIZE]; + BitmapFactory.Options options = BitmapUtil.createOptions(); + for (String path : paths) { + File sourcePath = new File(path); + if (!sourcePath.exists()) + continue; + try { + String name = sourcePath.getName(); + String ext = name.substring(name.lastIndexOf(".") + 1).toLowerCase(); + String tempFile = String.format("%s/IMG_%s.%s", cacheDir, System.currentTimeMillis(), ext); + if (PicturesCompressor.compressImage(path, tempFile, MAX_UPLOAD_LENGTH, + 80, 1280, 1280 * 6, buffer, options, true)) { + TweetPublishService.log("OPERATOR doImage " + tempFile + " " + new File(tempFile).length()); + + // verify the picture ext. + tempFile = PicturesCompressor.verifyPictureExt(tempFile); + + ret.add(tempFile); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + if (ret.size() > 0) { + String[] images = new String[ret.size()]; + ret.toArray(images); + return images; + } + return null; + } + + private void saveError(String cmd, String log) { + model.setErrorString(String.format("%s | %s", cmd, log)); + // update to cache file save error log + service.updateModelCache(model.getId(), model); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/tweet/service/TweetPublishService.java b/app/src/main/java/net/oschina/app/improve/tweet/service/TweetPublishService.java new file mode 100644 index 0000000000000000000000000000000000000000..20bb86a876ffd5054d16cfbe5c29ce73a3d73f94 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/tweet/service/TweetPublishService.java @@ -0,0 +1,384 @@ +package net.oschina.app.improve.tweet.service; + +import android.app.Notification; +import android.app.PendingIntent; +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.support.annotation.Nullable; +import android.support.v4.app.NotificationCompat; +import android.support.v4.app.NotificationManagerCompat; +import android.support.v4.util.ArrayMap; + +import net.oschina.app.AppContext; +import net.oschina.app.R; +import net.oschina.app.api.ApiHttpClient; +import net.oschina.app.improve.bean.simple.About; +import net.oschina.app.util.TLog; +import net.oschina.common.utils.CollectionUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 动弹发布服务 + * 专用于动弹发布 + */ +public class TweetPublishService extends Service implements Contract.IService { + private final static String TAG = TweetPublishService.class.getName(); + + public static final String ACTION_RECEIVER_SEARCH_INCOMPLETE = "net.oschina.app.improve.tweet.service.action.receiver.SEARCH_INCOMPLETE"; + public static final String ACTION_RECEIVER_SEARCH_FAILED = "net.oschina.app.improve.tweet.service.action.receiver.SEARCH_FAILED"; + + private static final String ACTION_PUBLISH = "net.oschina.app.improve.tweet.service.action.PUBLISH"; + private static final String ACTION_CONTINUE = "net.oschina.app.improve.tweet.service.action.CONTINUE"; + private static final String ACTION_DELETE = "net.oschina.app.improve.tweet.service.action.DELETE"; + + private static final String EXTRA_CONTENT = "net.oschina.app.improve.tweet.service.extra.CONTENT"; + private static final String EXTRA_IMAGES = "net.oschina.app.improve.tweet.service.extra.IMAGES"; + private static final String EXTRA_ABOUT = "net.oschina.app.improve.tweet.service.extra.ABOUT"; + private static final String EXTRA_ID = "net.oschina.app.improve.tweet.service.extra.ID"; + public static final String EXTRA_IDS = "net.oschina.app.improve.tweet.service.extra.IDS"; + + private volatile Looper mServiceLooper; + private volatile ServiceHandler mServiceHandler; + private Map mRunTasks = new ArrayMap<>(); + + private int mTaskCount; + private volatile boolean mDoAddTask = false; + + private final class ServiceHandler extends Handler { + ServiceHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + onHandleIntent((Intent) msg.obj, msg.arg1); + } + } + + + /** + * 发起动弹发布服务 + *

    + * 如果发布的动弹绑定到相关资讯等,则About节点不为NULL + * 仅仅关注:{@link About.Share#id}, {@link About.Share#type}}, + * {@link About.Share#commitTweetId}, {@link About.Share#fromTweetId} + */ + public static void startActionPublish(Context context, String content, List images, About.Share aboutShare) { + Intent intent = new Intent(context, TweetPublishService.class); + intent.setAction(ACTION_PUBLISH); + intent.putExtra(EXTRA_CONTENT, content); + if (images != null && images.size() > 0) { + String[] pubImages = new String[images.size()]; + images.toArray(pubImages); + intent.putExtra(EXTRA_IMAGES, pubImages); + } + if (About.check(aboutShare)) { + intent.putExtra(EXTRA_ABOUT, aboutShare); + } + context.startService(intent); + } + + /** + * 继续发送动弹 + * + * @param context Context + * @param modelId {@link TweetPublishModel#id} + */ + public static void startActionContinue(Context context, String modelId) { + Intent intent = new Intent(context, TweetPublishService.class); + intent.setAction(ACTION_CONTINUE); + intent.putExtra(EXTRA_ID, modelId); + context.startService(intent); + } + + /** + * 删除该动弹 + * + * @param context Context + * @param modelId {@link TweetPublishModel#id} + */ + public static void startActionDelete(Context context, String modelId) { + Intent intent = new Intent(context, TweetPublishService.class); + intent.setAction(ACTION_DELETE); + intent.putExtra(EXTRA_ID, modelId); + context.startService(intent); + } + + + /** + * 查询发送失败动 + * 如果有将通过广播{@link #ACTION_RECEIVER_SEARCH_FAILED}通知 + */ + public static void startActionSearchFailed(Context context) { + Intent intent = new Intent(context, TweetPublishService.class); + intent.setAction(ACTION_RECEIVER_SEARCH_FAILED); + context.startService(intent); + } + + public TweetPublishService() { + } + + private void addTask(int startId) { + mDoAddTask = true; + synchronized (TweetPublishService.this) { + mTaskCount = mTaskCount + 1; + log("removeTask:" + startId + " count:" + mTaskCount); + } + mDoAddTask = false; + } + + private void removeTask(int startId) { + synchronized (TweetPublishService.this) { + mTaskCount = mTaskCount - 1; + log("removeTask:" + startId + " count:" + mTaskCount + " doAdd:" + mDoAddTask); + if (mTaskCount == 0 && !mDoAddTask) + stopSelf(); + } + } + + @Override + public void onCreate() { + super.onCreate(); + log("onCreate"); + + // init sync client + ApiHttpClient.init((AppContext) getApplication()); + + HandlerThread thread = new HandlerThread(TweetPublishService.class.getSimpleName()); + thread.start(); + + mServiceLooper = thread.getLooper(); + mServiceHandler = new ServiceHandler(mServiceLooper); + } + + /** + * You should not override this method for your IntentService. Instead, + * override {@link #onHandleIntent}, which the system calls when the IntentService + * receives a start request. + * + * @see android.app.Service#onStartCommand + */ + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + // In this, we add the task count + addTask(startId); + // Do message + Message msg = mServiceHandler.obtainMessage(); + msg.arg1 = startId; + msg.obj = intent; + mServiceHandler.sendMessage(msg); + return super.onStartCommand(intent, flags, startId); + } + + @Override + public void onDestroy() { + super.onDestroy(); + mServiceLooper.quit(); + log("onDestroy"); + } + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return null; + } + + /** + * 在线程中处理请求数据 + * + * @param intent 请求的数据 + * @param startId 启动服务的Id + */ + private void onHandleIntent(Intent intent, int startId) { + if (intent != null) { + final String action = intent.getAction(); + log("onHandleIntent:" + startId); + log(action); + + if (ACTION_PUBLISH.equals(action)) { + final String content = intent.getStringExtra(EXTRA_CONTENT); + final String[] images = intent.getStringArrayExtra(EXTRA_IMAGES); + final About.Share share = (About.Share) intent.getSerializableExtra(EXTRA_ABOUT); + handleActionPublish(content, images, share, startId); + } else { + if (ACTION_CONTINUE.equals(action)) { + final String id = intent.getStringExtra(EXTRA_ID); + if (id == null || handleActionContinue(id, startId)) { + removeTask(startId); + } + } else if (ACTION_DELETE.equals(action)) { + final String id = intent.getStringExtra(EXTRA_ID); + if (id == null || handleActionDelete(id, startId)) { + removeTask(startId); + } + } else if (ACTION_RECEIVER_SEARCH_FAILED.equals(action)) { + handleActionSearch(); + removeTask(startId); + } + } + } + } + + /** + * 发布动弹,在后台服务中进行 + */ + private void handleActionPublish(String content, String[] images, About.Share share, int startId) { + TweetPublishModel model = new TweetPublishModel(content, images, share); + TweetPublishCache.save(getApplicationContext(), model.getId(), model); + Contract.IOperator operator = new TweetPublishOperator(model, this, startId); + operator.run(); + } + + /** + * 继续发送动弹 + * + * @param id 动弹Id + * @param startId 服务Id + * @return 返回是否销毁当前服务 + */ + private boolean handleActionContinue(String id, int startId) { + Contract.IOperator operator = mRunTasks.get(id); + if (operator != null) { + // 正在运行, 不做操作 + return true; + } + TweetPublishModel model = TweetPublishCache.get(getApplicationContext(), id); + if (model != null) { + operator = new TweetPublishOperator(model, this, startId); + operator.run(); + return false; + } + return true; + } + + /** + * 移除动弹 + * 该动弹的缓存将进行清空 + * + * @param id 动弹Id + * @param startId 服务Id + * @return 返回是否销毁当前服务 + */ + private boolean handleActionDelete(String id, int startId) { + Contract.IOperator operator = mRunTasks.get(id); + if (operator != null) + operator.stop(); + TweetPublishCache.remove(getApplicationContext(), id); + // In this we need remove the notify + notifyCancel(id.hashCode()); + return true; + } + + /** + * 进行查询操作, + * 查询当前发送失败的动弹 + */ + private boolean handleActionSearch() { + List models = TweetPublishCache.list(getApplicationContext()); + if (models == null || models.size() == 0) + return false; + + final Map runningMap = mRunTasks; + List ids = new ArrayList<>(); + + for (TweetPublishModel model : models) { + if (!runningMap.containsKey(model.getId())) { + ids.add(model.getId()); + } + } + + // If have failed task, we need callback + if (ids.size() > 0) { + Intent intent = new Intent(ACTION_RECEIVER_SEARCH_FAILED); + intent.putExtra(EXTRA_IDS, CollectionUtil.toArray(ids, String.class)); + sendBroadcast(intent); + return true; + } + + return false; + } + + @Override + public String getCachePath(String id) { + return TweetPublishCache.getImageCachePath(getApplicationContext(), id); + } + + @Override + public void start(String id, Contract.IOperator operator) { + if (!mRunTasks.containsKey(id)) { + mRunTasks.put(id, operator); + } + } + + @Override + public void stop(String id, int startId) { + if (mRunTasks.containsKey(id)) { + mRunTasks.remove(id); + } + // stop self + removeTask(startId); + } + + @Override + public void updateModelCache(String id, TweetPublishModel model) { + if (model == null) + TweetPublishCache.remove(getApplicationContext(), id); + else + TweetPublishCache.save(getApplicationContext(), id, model); + } + + @Override + public void notifyMsg(int notifyId, String modelId, boolean haveReDo, boolean haveDelete, int resId, Object... values) { + PendingIntent contentIntent = null; + if (haveReDo) { + Intent intent = new Intent(this, TweetPublishService.class); + intent.setAction(ACTION_CONTINUE); + intent.putExtra(EXTRA_ID, modelId); + contentIntent = PendingIntent.getService(getApplicationContext(), notifyId, intent, PendingIntent.FLAG_UPDATE_CURRENT); + } + + PendingIntent deleteIntent = null; + if (haveDelete) { + Intent intent = new Intent(this, TweetPublishService.class); + intent.setAction(ACTION_DELETE); + intent.putExtra(EXTRA_ID, modelId); + deleteIntent = PendingIntent.getService(getApplicationContext(), notifyId, intent, PendingIntent.FLAG_UPDATE_CURRENT); + } + + String content = getString(resId, values); + + NotificationCompat.Builder builder = new NotificationCompat.Builder( + this) + .setTicker(content) + .setContentTitle(getString(R.string.tweet_publish_title)) + .setContentText(content) + .setAutoCancel(haveDelete) + .setOngoing(!haveReDo) + .setContentIntent(contentIntent) + .setDeleteIntent(deleteIntent) + .setSmallIcon(R.mipmap.ic_notification); + + Notification notification = builder.build(); + NotificationManagerCompat.from(this).notify(notifyId, notification); + + log(content); + } + + @Override + public void notifyCancel(int notifyId) { + NotificationManagerCompat.from(this).cancel(notifyId); + } + + public static void log(String str) { + TLog.log(TAG, str); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/tweet/widget/ClipView.java b/app/src/main/java/net/oschina/app/improve/tweet/widget/ClipView.java new file mode 100644 index 0000000000000000000000000000000000000000..bf5590a441ee993483471de5716c39d4ee1f3481 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/tweet/widget/ClipView.java @@ -0,0 +1,264 @@ +package net.oschina.app.improve.tweet.widget; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.Rect; +import android.os.Build; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.Interpolator; +import android.widget.FrameLayout; + +import net.qiujuer.genius.ui.Ui; + +/** + * Created by JuQiu + * on 16/8/22. + */ +public class ClipView extends FrameLayout implements ValueAnimator.AnimatorUpdateListener { + private static boolean IS_UP_KITKAT = false;//Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; + private Path mPath; + private boolean mInAnim = IS_UP_KITKAT; + private float mStartRadius, mEndRadius; + private float mStartPointX, mEndPointX; + private float mStartPointY, mEndPointY; + private int mColor; + private float mProgress; + + private int[] mStartLocation; + private int[] mStartSize; + + public ClipView(Context context) { + super(context); + } + + public ClipView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public ClipView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public void setup(int[] startLocation, int[] startSize) { + if (startLocation == null) + startLocation = new int[]{0, 0}; + if (startSize == null) + startSize = new int[]{0, 0}; + mStartLocation = startLocation; + mStartSize = startSize; + requestLayout(); + } + + + @Override + protected void dispatchDraw(Canvas canvas) { + if (!IS_UP_KITKAT) { + super.dispatchDraw(canvas); + return; + } + if (mProgress <= 0) + return; + if (mInAnim && mPath != null) { + int saveCount = canvas.save(); + canvas.clipPath(mPath); + super.dispatchDraw(canvas); + canvas.drawColor(mColor); + canvas.restoreToCount(saveCount); + } else { + super.dispatchDraw(canvas); + } + } + + @Override + public void setLayerType(int layerType, Paint paint) { + if (paint == null && getLayerType() == layerType) { + return; + } + if (IS_UP_KITKAT) + layerType = View.LAYER_TYPE_SOFTWARE; + super.setLayerType(layerType, paint); + } + + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + if (mStartLocation == null || mStartSize == null) + return; + + int[] selfLocation = new int[2]; + getLocationOnScreen(selfLocation); + + int pointX = mStartLocation[0] - selfLocation[0]; + int pointY = mStartLocation[1] - selfLocation[1]; + + int sizePointX = mStartSize[0] >> 1; + int sizePointY = mStartSize[1] >> 1; + + mStartPointX = pointX + sizePointX; + mStartPointY = pointY + sizePointY; + + // Check the point by start + if (mStartPointX < 0) { + mStartPointX = sizePointX; + } + if (mStartPointX > w) { + mStartPointX = w - sizePointX; + } + if (mStartPointY < 0) { + mStartPointY = sizePointY; + } + if (mStartPointY > h) { + mStartPointY = h - sizePointY; + } + + // End + mEndPointX = w >> 1; + mEndPointY = h >> 1; + + mStartRadius = Math.min(sizePointX, sizePointY); + mEndRadius = (float) Math.sqrt(mEndPointY * mEndPointY + mEndPointX * mEndPointX); + } + + + private void doUpdate(float progress) { + mColor = Ui.changeColorAlpha(0x24cf5f, (int) (240 - (240 * progress))); + + Path path = mPath; + path.reset(); + float radius = mStartRadius + (mEndRadius - mStartRadius) * progress; + float pointX = mStartPointX + (mEndPointX - mStartPointX) * progress; + float pointY = mStartPointY + (mEndPointY - mStartPointY) * progress; + path.addCircle(pointX, pointY, radius, Path.Direction.CW); + invalidate(); + } + + private ValueAnimator mAnimator; + + private ValueAnimator getAnimator(boolean isEnter, int time, Runnable runnable) { + mDoRunnable = runnable; + final float nowProgress = mProgress; + + if (mAnimator == null) { + ValueAnimator animation = ValueAnimator.ofFloat(nowProgress, isEnter ? 1f : 0f); + animation.addUpdateListener(this); + animation.addListener(mAnimatorListenerAdapter); + mAnimator = animation; + } else { + mAnimator.cancel(); + mAnimator.setFloatValues(nowProgress, isEnter ? 1f : 0f); + } + + Interpolator interpolator; + if (isEnter) + interpolator = new DecelerateInterpolator(); + else + interpolator = new AccelerateInterpolator(); + mAnimator.setInterpolator(interpolator); + mAnimator.setDuration((long) (time * (isEnter ? 1 - nowProgress : nowProgress))); + + return mAnimator; + } + + public void start(Runnable runnable) { + if (!IS_UP_KITKAT) { + runnable.run(); + return; + } + + if (mPath == null) { + mPath = new Path(); + setLayerType(View.LAYER_TYPE_SOFTWARE, null); + } + + getAnimator(true, 480, runnable).start(); + } + + public void exit(Runnable runnable) { + if (!IS_UP_KITKAT) { + runnable.run(); + return; + } + + if (mPath == null) { + mPath = new Path(); + setLayerType(View.LAYER_TYPE_SOFTWARE, null); + } + + getAnimator(false, 380, runnable).start(); + } + + @Override + protected final boolean fitSystemWindows(Rect insets) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + insets.left = 0; + insets.top = 0; + insets.right = 0; + } + return super.fitSystemWindows(insets); + } + + /* + @Override + public final WindowInsets onApplyWindowInsets(WindowInsets insets) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) { + insets = insets.replaceSystemWindowInsets(0, 0, 0, + insets.getSystemWindowInsetBottom()); + } + return insets; + } + */ + + /** + * If in animation or finish state, we InterceptTouchEvent + * + * @param ev ev + * @return can do + */ + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + return !mInAnim && super.dispatchTouchEvent(ev); + } + + @Override + public void onAnimationUpdate(ValueAnimator animation) { + mProgress = (float) animation.getAnimatedValue(); + doUpdate(mProgress); + } + + private Runnable mDoRunnable; + + private AnimatorListenerAdapter mAnimatorListenerAdapter = new AnimatorListenerAdapter() { + private boolean isCancel; + + @Override + public void onAnimationCancel(Animator animation) { + isCancel = true; + } + + @Override + public void onAnimationStart(Animator animation) { + mInAnim = true; + isCancel = false; + } + + @Override + public void onAnimationEnd(Animator animation) { + mInAnim = false; + Runnable runnable = mDoRunnable; + if (!isCancel && runnable != null) { + runnable.run(); + mDoRunnable = null; + } + } + }; +} diff --git a/app/src/main/java/net/oschina/app/improve/tweet/widget/TweetPicturesPreviewer.java b/app/src/main/java/net/oschina/app/improve/tweet/widget/TweetPicturesPreviewer.java new file mode 100644 index 0000000000000000000000000000000000000000..1f80e12d0ef392431bc526810eb983aa50dd1107 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/tweet/widget/TweetPicturesPreviewer.java @@ -0,0 +1,98 @@ +package net.oschina.app.improve.tweet.widget; + +import android.content.Context; +import android.support.annotation.Nullable; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.helper.ItemTouchHelper; +import android.util.AttributeSet; +import android.view.View; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.RequestManager; + +import net.oschina.app.improve.media.SelectImageActivity; +import net.oschina.app.improve.media.config.SelectOptions; +import net.oschina.app.improve.tweet.adapter.TweetSelectImageAdapter; + +/** + * Created by JuQiu + * on 16/7/18. + *

    + * 动弹发布界面, 图片预览器 + *

    + * 提供图片预览/图片操作 返回选中图片等功能 + */ + +public class TweetPicturesPreviewer extends RecyclerView implements TweetSelectImageAdapter.Callback { + private TweetSelectImageAdapter mImageAdapter; + private ItemTouchHelper mItemTouchHelper; + private RequestManager mCurImageLoader; + + public TweetPicturesPreviewer(Context context) { + super(context); + init(); + } + + public TweetPicturesPreviewer(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + init(); + } + + public TweetPicturesPreviewer(Context context, @Nullable AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + private void init() { + mImageAdapter = new TweetSelectImageAdapter(this); + + GridLayoutManager layoutManager = new GridLayoutManager(getContext(), 3); + this.setLayoutManager(layoutManager); + this.setAdapter(mImageAdapter); + this.setOverScrollMode(View.OVER_SCROLL_NEVER); + + ItemTouchHelper.Callback callback = new TweetPicturesPreviewerItemTouchCallback(mImageAdapter); + mItemTouchHelper = new ItemTouchHelper(callback); + mItemTouchHelper.attachToRecyclerView(this); + } + + public void set(String[] paths) { + mImageAdapter.clear(); + for (String path : paths) { + mImageAdapter.add(path); + } + mImageAdapter.notifyDataSetChanged(); + } + + @Override + public void onLoadMoreClick() { + SelectImageActivity.show(getContext(), new SelectOptions.Builder() + .setHasCam(true) + .setSelectCount(9) + .setSelectedImages(mImageAdapter.getPaths()) + .setCallback(new SelectOptions.Callback() { + @Override + public void doSelected(String[] images) { + set(images); + } + }).build()); + } + + @Override + public RequestManager getImgLoader() { + if (mCurImageLoader == null) { + mCurImageLoader = Glide.with(getContext()); + } + return mCurImageLoader; + } + + @Override + public void onStartDrag(ViewHolder viewHolder) { + mItemTouchHelper.startDrag(viewHolder); + } + + public String[] getPaths() { + return mImageAdapter.getPaths(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/tweet/widget/TweetPicturesPreviewerItemTouchCallback.java b/app/src/main/java/net/oschina/app/improve/tweet/widget/TweetPicturesPreviewerItemTouchCallback.java new file mode 100644 index 0000000000000000000000000000000000000000..838b46e05b308f83ebb4c15e7caf46ed1e05a265 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/tweet/widget/TweetPicturesPreviewerItemTouchCallback.java @@ -0,0 +1,164 @@ +package net.oschina.app.improve.tweet.widget; + +import android.graphics.Canvas; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.helper.ItemTouchHelper; + +/** + * Created by JuQiu + * on 16/7/18. + *

    + * An implementation of {@link ItemTouchHelper.Callback} that enables basic drag & drop and + * swipe-to-dismiss. Drag events are automatically started by an item long-press.
    + *
    + * Expects the RecyclerView.Adapter to listen for {@link + * ItemTouchHelperAdapter} callbacks and the RecyclerView.ViewHolder to implement + * {@link ItemTouchHelperViewHolder}. + */ + +public class TweetPicturesPreviewerItemTouchCallback extends ItemTouchHelper.Callback { + + public static final float ALPHA_FULL = 1.0f; + + private final ItemTouchHelperAdapter mAdapter; + + public TweetPicturesPreviewerItemTouchCallback(ItemTouchHelperAdapter adapter) { + mAdapter = adapter; + } + + @Override + public boolean isLongPressDragEnabled() { + return false; + } + + @Override + public boolean isItemViewSwipeEnabled() { + return false; + } + + @Override + public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { + // Set movement flags based on the layout manager + if (recyclerView.getLayoutManager() instanceof GridLayoutManager) { + final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; + final int swipeFlags = 0; + return makeMovementFlags(dragFlags, swipeFlags); + } else { + final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; + final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END; + return makeMovementFlags(dragFlags, swipeFlags); + } + } + + @Override + public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) { + if (source.getItemViewType() != target.getItemViewType()) { + return false; + } + + // Notify the adapter of the move + mAdapter.onItemMove(source.getAdapterPosition(), target.getAdapterPosition()); + return true; + } + + @Override + public void onSwiped(RecyclerView.ViewHolder viewHolder, int i) { + // Notify the adapter of the dismissal + mAdapter.onItemDismiss(viewHolder.getAdapterPosition()); + } + + @Override + public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { + if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { + // Fade out the view as it is swiped out of the parent's bounds + final float alpha = ALPHA_FULL - Math.abs(dX) / (float) viewHolder.itemView.getWidth(); + viewHolder.itemView.setAlpha(alpha); + viewHolder.itemView.setTranslationX(dX); + } else { + super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); + } + } + + @Override + public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { + // We only want the active item to change + if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) { + if (viewHolder instanceof ItemTouchHelperViewHolder) { + // Let the view holder know that this item is being moved or dragged + ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder; + itemViewHolder.onItemSelected(); + } + } + + super.onSelectedChanged(viewHolder, actionState); + } + + @Override + public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { + super.clearView(recyclerView, viewHolder); + + viewHolder.itemView.setAlpha(ALPHA_FULL); + + if (viewHolder instanceof ItemTouchHelperViewHolder) { + // Tell the view holder it's time to restore the idle state + ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder; + itemViewHolder.onItemClear(); + } + } + + /** + * Interface to listen for a move or dismissal event from a {@link ItemTouchHelper.Callback}. + */ + public interface ItemTouchHelperAdapter { + + /** + * Called when an item has been dragged far enough to trigger a move. This is called every time + * an item is shifted, and not at the end of a "drop" event.
    + *
    + * Implementations should call {@link RecyclerView.Adapter#notifyItemMoved(int, int)} after + * adjusting the underlying data to reflect this move. + * + * @param fromPosition The start position of the moved item. + * @param toPosition Then resolved position of the moved item. + * @return True if the item was moved to the new adapter position. + * @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder) + * @see RecyclerView.ViewHolder#getAdapterPosition() + */ + boolean onItemMove(int fromPosition, int toPosition); + + + /** + * Called when an item has been dismissed by a swipe.
    + *
    + * Implementations should call {@link RecyclerView.Adapter#notifyItemRemoved(int)} after + * adjusting the underlying data to reflect this removal. + * + * @param position The position of the item dismissed. + * @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder) + * @see RecyclerView.ViewHolder#getAdapterPosition() + */ + void onItemDismiss(int position); + } + + + /** + * Interface to notify an item ViewHolder of relevant callbacks from {@link + * android.support.v7.widget.helper.ItemTouchHelper.Callback}. + */ + public interface ItemTouchHelperViewHolder { + + /** + * Called when the {@link ItemTouchHelper} first registers an item as being moved or swiped. + * Implementations should update the item view to indicate it's active state. + */ + void onItemSelected(); + + + /** + * Called when the {@link ItemTouchHelper} has completed the move or swipe, and the active item + * state should be cleared. + */ + void onItemClear(); + } +} \ No newline at end of file diff --git a/app/src/main/java/net/oschina/app/improve/user/activities/OtherUserHomeActivity.java b/app/src/main/java/net/oschina/app/improve/user/activities/OtherUserHomeActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..849cff86548082b0f6ea41019007abcc1f65ddfd --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/activities/OtherUserHomeActivity.java @@ -0,0 +1,563 @@ +package net.oschina.app.improve.user.activities; + +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.graphics.Rect; +import android.os.Build; +import android.os.Bundle; +import android.support.design.widget.AppBarLayout; +import android.support.design.widget.TabLayout; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentStatePagerAdapter; +import android.support.v4.view.ViewPager; +import android.support.v7.widget.Toolbar; +import android.text.TextUtils; +import android.util.Pair; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.AppContext; +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.bean.SimpleBackPage; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.base.activities.BaseActivity; +import net.oschina.app.improve.bean.User; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.bean.simple.Author; +import net.oschina.app.improve.bean.simple.UserRelation; +import net.oschina.app.improve.tweet.fragments.TweetFragment; +import net.oschina.app.improve.user.fragments.UserActiveFragment; +import net.oschina.app.improve.user.fragments.UserBlogFragment; +import net.oschina.app.improve.user.fragments.UserQuestionFragment; +import net.oschina.app.improve.utils.DialogHelper; +import net.oschina.app.improve.widget.SolarSystemView; +import net.oschina.app.util.UIHelper; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import butterknife.Bind; +import cz.msebera.android.httpclient.Header; +import de.hdodenhof.circleimageview.CircleImageView; + +/** + * 别的用户的主页 + * Created by thanatos on 16/7/13. + */ +public class OtherUserHomeActivity extends BaseActivity + implements View.OnClickListener, DialogInterface.OnClickListener { + + public static final String KEY_BUNDLE = "KEY_BUNDLE_IN_OTHER_USER_HOME"; + + /* 谁格式化了我这里的代码我就打谁 */ + @Bind(R.id.toolbar) + Toolbar mToolbar; + @Bind(R.id.iv_portrait) + CircleImageView mPortrait; + @Bind(R.id.tv_nick) + TextView mNick; + @Bind(R.id.tv_summary) + TextView mSummary; + @Bind(R.id.tv_score) + TextView mScore; + @Bind(R.id.tv_count_follow) + TextView mCountFollow; + @Bind(R.id.tv_count_fans) + TextView mCountFans; + @Bind(R.id.view_solar_system) + SolarSystemView mSolarSystem; + @Bind(R.id.layout_appbar) + AppBarLayout mLayoutAppBar; + @Bind(R.id.iv_logo_portrait) + CircleImageView mLogoPortrait; + @Bind(R.id.tv_logo_nick) + TextView mLogoNick; + @Bind(R.id.iv_gender) + ImageView mGenderImage; + @Bind(R.id.layout_tab) + TabLayout mTabLayout; + @Bind(R.id.view_pager) + ViewPager mViewPager; + @Bind(R.id.view_divider) + View mDivider; + + private User user; + private MenuItem mFollowMenu; + private List> fragments; + private TabLayoutOffsetChangeListener mOffsetChangerListener; + + public static void show(Context context, Author author) { + if (author == null) return; + User user = new User(); + user.setId(author.getId()); + user.setName(author.getName()); + user.setPortrait(author.getPortrait()); + show(context, user); + } + + public static void show(Context context, long id) { + if (id <= 0) return; + User user = new User(); + user.setId((int) id); + show(context, user); + } + + public static void show(Context context, String nick) { + if (TextUtils.isEmpty(nick)) return; + User user = new User(); + user.setName(nick); + show(context, user); + } + + /** + * @param context context + * @param id 无效值,随便填,只是用来区别{{@link #show(Context, String)}}方法的 + * @param suffix 个性后缀 + */ + public static void show(Context context, long id, String suffix) { + if (TextUtils.isEmpty(suffix)) return; + User user = new User(); + user.setSuffix(suffix); + show(context, user); + } + + public static void show(Context context, User user) { + if (user == null) return; + Intent intent = new Intent(context, OtherUserHomeActivity.class); + intent.putExtra(KEY_BUNDLE, user); + context.startActivity(intent); + } + + @Override + protected boolean initBundle(Bundle bundle) { + user = (User) bundle.getSerializable(KEY_BUNDLE); + if (user == null || (user.getId() <= 0 && TextUtils.isEmpty(user.getName()) + && TextUtils.isEmpty(user.getSuffix()))) { + Toast.makeText(this, "没有此用户", Toast.LENGTH_SHORT).show(); + return false; + } + return super.initBundle(bundle); + } + + @Override + protected int getContentView() { + return R.layout.activity_other_user_home; + } + + @Override + protected void initWidget() { + super.initWidget(); + mToolbar.setTitle(""); + mToolbar.setSubtitle(""); + mToolbar.setNavigationIcon(R.mipmap.btn_back_normal); + setSupportActionBar(mToolbar); + mToolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + + mLayoutAppBar.addOnOffsetChangedListener(mOffsetChangerListener = new TabLayoutOffsetChangeListener()); + + mPortrait.post(new Runnable() { + @Override + public void run() { + int mStatusBarHeight = 0; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + Rect rectangle = new Rect(); + Window window = getWindow(); + window.getDecorView().getWindowVisibleDisplayFrame(rectangle); + mStatusBarHeight = rectangle.top; + } + float x = mPortrait.getX(); + float y = mPortrait.getY(); + ViewGroup parent = (ViewGroup) mPortrait.getParent(); + float px = x + parent.getX() + mPortrait.getWidth() / 2; + float py = y + parent.getY() + mPortrait.getHeight() / 2 + mStatusBarHeight; + int mMaxRadius = (int) (mSolarSystem.getHeight() - py + 50); + + int r = mPortrait.getWidth() / 2; + Random random = new Random(System.currentTimeMillis()); + for (int i = 60, radius = r + i; ; i = (int) (i * 1.4), radius += i) { + SolarSystemView.Planet planet = new SolarSystemView.Planet(); + planet.setClockwise(random.nextInt(10) % 2 == 0); + planet.setAngleRate((random.nextInt(35) + 1) / 1000.f); + planet.setRadius(radius); + mSolarSystem.addPlanets(planet); + if (radius > mMaxRadius) break; + } + mSolarSystem.setPivotPoint(px, py); + float ry = mSolarSystem.getHeight() - py; + double rx = Math.pow(px * px + ry * ry, 1.f / 2.f); + mSolarSystem.setRadialGradient(px, py, (float) rx, 0XFF24CF5F, 0XFF20B955); + } + }); + + mTabLayout.addTab(mTabLayout.newTab().setCustomView(getTabView("0", "动弹"))); + mTabLayout.addTab(mTabLayout.newTab().setCustomView(getTabView("0", "博客"))); + mTabLayout.addTab(mTabLayout.newTab().setCustomView(getTabView("0", "问答"))); + mTabLayout.addTab(mTabLayout.newTab().setCustomView(getTabView("0", "讨论"))); + injectDataToView(); + injectDataToViewPager(); + } + + @SuppressWarnings("all") + private void injectDataToViewPager() { + if (user.getId() <= 0) return; + + int t = 0, b = 0, a = 0, d = 0; + if (user.getStatistics() != null) { + t = user.getStatistics().getTweet(); + b = user.getStatistics().getBlog(); + a = user.getStatistics().getAnswer(); + d = user.getStatistics().getDiscuss(); + } + + if (fragments == null) { + fragments = new ArrayList<>(); + fragments.add(new Pair<>( + String.format("%s\n动弹", 0), + TweetFragment.instantiate(user.getId(), 0))); + fragments.add(new Pair<>( + String.format("%s\n博客", 0), + UserBlogFragment.instantiate(user.getId()))); + fragments.add(new Pair<>( + String.format("%s\n问答", 0), + UserQuestionFragment.instantiate((int) user.getId()))); + fragments.add(new Pair<>( + String.format("%s\n讨论", 0), + UserActiveFragment.instantiate(user.getId()))); + + mViewPager.setAdapter(new FragmentStatePagerAdapter(getSupportFragmentManager()) { + @Override + public Fragment getItem(int position) { + return fragments.get(position).second; + } + + @Override + public int getCount() { + return fragments.size(); + } + + @Override + public CharSequence getPageTitle(int position) { + return fragments.get(position).first; + } + }); + + mTabLayout.setupWithViewPager(mViewPager); + // TabLayout will remove up all tabs after setted up view pager + // so we set it again + mTabLayout.getTabAt(0).setCustomView(getTabView(formatNumeric(t), "动弹")); + mTabLayout.getTabAt(1).setCustomView(getTabView(formatNumeric(b), "博客")); + mTabLayout.getTabAt(2).setCustomView(getTabView(formatNumeric(a), "问答")); + mTabLayout.getTabAt(3).setCustomView(getTabView(formatNumeric(d), "讨论")); + } else { // when request user detail info successfully + setupTabText(mTabLayout.getTabAt(0), t); + setupTabText(mTabLayout.getTabAt(1), b); + setupTabText(mTabLayout.getTabAt(2), a); + setupTabText(mTabLayout.getTabAt(3), d); + } + } + + @SuppressWarnings("all") + private void setupTabText(TabLayout.Tab tab, int count) { + View view = tab.getCustomView(); + if (view == null) return; + TabViewHolder holder = (TabViewHolder) view.getTag(); + holder.mViewCount.setText(formatNumeric(count)); + } + + private String formatNumeric(int count) { + if (count > 1000) { + int a = count / 100; + int b = a % 10; + int c = a / 10; + String str; + if (c <= 9 && b != 0) str = c + "." + b; + else str = String.valueOf(c); + return str + "k"; + } else { + return String.valueOf(count); + } + } + + private View getTabView(String cs, String tag) { + View view = LayoutInflater.from(this).inflate(R.layout.tab_item_other_user, mTabLayout, false); + TabViewHolder holder = new TabViewHolder(view); + holder.mViewCount.setText(cs); + holder.mViewTag.setText(tag); + view.setTag(holder); + return view; + } + + private void injectDataToView() { + getImageLoader() + .load(user.getPortrait()) + .asBitmap() + .placeholder(R.mipmap.widget_dface) + .error(R.mipmap.widget_dface) + .into(mPortrait); + getImageLoader() + .load(user.getPortrait()) + .asBitmap() + .placeholder(R.mipmap.widget_dface) + .error(R.mipmap.widget_dface) + .into(mLogoPortrait); + mLogoNick.setText(user.getName()); + mNick.setText(user.getName()); + String desc = user.getDesc(); + mSummary.setText(TextUtils.isEmpty(desc) ? "这人很懒,什么都没写" : desc); + if (user.getStatistics() != null) { + mScore.setText(String.format("积分 %s", user.getStatistics().getScore())); + mCountFans.setText(String.format("粉丝 %s", user.getStatistics().getFans())); + mCountFollow.setText(String.format("关注 %s", user.getStatistics().getFollow())); + } else { + mScore.setText("积分 0"); + mCountFans.setText("粉丝 0"); + mCountFollow.setText("关注 0"); + } + + mGenderImage.setVisibility(View.VISIBLE); + if (user.getGender() == User.GENDER_MALE) { + mGenderImage.setImageResource(R.mipmap.ic_male); + } else if (user.getGender() == User.GENDER_FEMALE) { + mGenderImage.setImageResource(R.mipmap.ic_female); + } else { + mGenderImage.setVisibility(View.GONE); + } + + mOffsetChangerListener.resetRange(); + } + + @Override + protected void initData() { + super.initData(); + OSChinaApi.getUserInfo(user.getId(), user.getName(), user.getSuffix(), new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + Toast.makeText(OtherUserHomeActivity.this, "获取用户信息失败", Toast.LENGTH_SHORT).show(); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + ResultBean result = AppOperator.createGson().fromJson( + responseString, new TypeToken>() { + }.getType()); + if (result.isSuccess() && result.getResult() == null) return; + user = result.getResult(); + if (user == null) { + Toast.makeText(OtherUserHomeActivity.this, "该用户不存在", Toast.LENGTH_SHORT).show(); + finish(); + return; + } + injectDataToView(); + injectDataToViewPager(); + // after request user successful we could get user id when the static method show passed in user name + // before which, we hide the menu + invalidateOptionsMenu(); + } + }); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + if (AccountHelper.isLogin() && user.getId() > 0 && AccountHelper.getUserId() != user.getId()) { + getMenuInflater().inflate(R.menu.menu_other_user, menu); + mFollowMenu = menu.getItem(1); + if (mFollowMenu == null) return false; + switch (user.getRelation()) { + case User.RELATION_TYPE_BOTH: + mFollowMenu.setIcon(getResources().getDrawable( + R.drawable.selector_user_following_botn)); + break; + case User.RELATION_TYPE_ONLY_FANS_HIM: + mFollowMenu.setIcon(getResources().getDrawable( + R.drawable.selector_user_following)); + break; + case User.RELATION_TYPE_ONLY_FANS_ME: + mFollowMenu.setIcon(getResources().getDrawable( + R.drawable.selector_user_follow)); + break; + case User.RELATION_TYPE_NULL: + mFollowMenu.setIcon(getResources().getDrawable( + R.drawable.selector_user_follow)); + break; + default: + mFollowMenu.setIcon(getResources().getDrawable( + R.drawable.selector_user_follow)); + } + return true; + } + return false; + } + + @Override + public void onClick(View v) { + if (user == null || user.getId() <= 0) return; + switch (v.getId()) { + case R.id.tv_count_follow: + UserFollowsActivity.show(this, user.getId()); + break; + case R.id.tv_count_fans: + UserFansActivity.show(this, user.getId()); + break; + case R.id.view_solar_system: + Bundle userBundle = new Bundle(); + userBundle.putSerializable("user_info", user); + UIHelper.showSimpleBack(this, SimpleBackPage.MY_INFORMATION_DETAIL, userBundle); + break; + case R.id.iv_portrait: + DialogHelper.getSelectDialog(this, "请选择操作", new String[]{"查看头像"}, "取消", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + if (user == null || TextUtils.isEmpty(user.getPortrait())) return; + UIHelper.showUserAvatar(OtherUserHomeActivity.this, user.getPortrait()); + } + }).show(); + break; + } + } + + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + switch (item.getItemId()) { + case R.id.menu_pm: + if (user.getId() == AccountHelper.getUserId()) { + AppContext.showToast("不能给自己发送留言:)"); + return true; + } + if (!AccountHelper.isLogin()) { + UIHelper.showLoginActivity(this); + return true; + } + UserSendMessageActivity.show(this, user); + break; + case R.id.menu_follow: + // 判断登录 + if (!AccountHelper.isLogin()) { + UIHelper.showLoginActivity(this); + return true; + } + String mDialogTitle; + switch (user.getRelation()) { + case User.RELATION_TYPE_BOTH: + mDialogTitle = "确定取消互粉吗?"; + break; + case User.RELATION_TYPE_ONLY_FANS_HIM: + mDialogTitle = "确定取消关注吗?"; + break; + case User.RELATION_TYPE_ONLY_FANS_ME: + mDialogTitle = "确定关注Ta吗?"; + break; + case User.RELATION_TYPE_NULL: + mDialogTitle = "确定关注Ta吗?"; + break; + default: + return false; + } + DialogHelper.getConfirmDialog(this, mDialogTitle, this).show(); + break; + } + return super.onOptionsItemSelected(item); + } + + @Override + public void onClick(DialogInterface dialog, int which) { + if (mFollowMenu == null) return; + OSChinaApi.addUserRelationReverse(user.getId(), new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString + , Throwable throwable) { + Toast.makeText(OtherUserHomeActivity.this, "操作失败", Toast.LENGTH_SHORT).show(); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + ResultBean result = AppOperator.createGson().fromJson( + responseString, new TypeToken>() { + }.getType()); + if (result.isSuccess()) { + int relation = result.getResult().getRelation(); + switch (relation) { + case User.RELATION_TYPE_BOTH: + mFollowMenu.setIcon(getResources().getDrawable( + R.drawable.selector_user_following_botn)); + break; + case User.RELATION_TYPE_ONLY_FANS_HIM: + mFollowMenu.setIcon(getResources().getDrawable( + R.drawable.selector_user_following)); + break; + case User.RELATION_TYPE_ONLY_FANS_ME: + mFollowMenu.setIcon(getResources().getDrawable( + R.drawable.selector_user_follow)); + break; + case User.RELATION_TYPE_NULL: + mFollowMenu.setIcon(getResources().getDrawable( + R.drawable.selector_user_follow)); + break; + } + user.setRelation(relation); + } else { + onFailure(statusCode, headers, responseString, null); + } + } + }); + } + + private static class TabViewHolder { + private TextView mViewCount; + private TextView mViewTag; + + public TabViewHolder(View view) { + mViewCount = (TextView) view.findViewById(R.id.tv_count); + mViewTag = (TextView) view.findViewById(R.id.tv_tag); + } + } + + private class TabLayoutOffsetChangeListener implements AppBarLayout.OnOffsetChangedListener { + boolean isShow = false; + int mScrollRange = -1; + + @Override + public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { + if (mScrollRange == -1) { + mScrollRange = appBarLayout.getTotalScrollRange(); + } + if (mScrollRange + verticalOffset == 0) { + mLogoNick.setVisibility(View.VISIBLE); + mLogoPortrait.setVisibility(View.VISIBLE); + mDivider.setVisibility(View.GONE); + isShow = true; + } else if (isShow) { + mLogoNick.setVisibility(View.GONE); + mLogoPortrait.setVisibility(View.GONE); + mDivider.setVisibility(View.VISIBLE); + isShow = false; + } + mTabLayout.getBackground().setAlpha( + Math.round(255 - Math.abs(verticalOffset) / (float) mScrollRange * 255)); + } + + public void resetRange() { + mScrollRange = -1; + } + } + +} diff --git a/app/src/main/java/net/oschina/app/improve/user/activities/UserCollectionActivity.java b/app/src/main/java/net/oschina/app/improve/user/activities/UserCollectionActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..968cefd9b5828d22a0bc7d2557f103e259a2fd4f --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/activities/UserCollectionActivity.java @@ -0,0 +1,116 @@ +package net.oschina.app.improve.user.activities; + +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; + +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.base.activities.BaseRecyclerViewActivity; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.bean.Collection; +import net.oschina.app.improve.bean.News; +import net.oschina.app.improve.bean.base.PageBean; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.detail.activities.BlogDetailActivity; +import net.oschina.app.improve.detail.activities.EventDetailActivity; +import net.oschina.app.improve.detail.activities.NewsDetailActivity; +import net.oschina.app.improve.detail.activities.QuestionDetailActivity; +import net.oschina.app.improve.detail.activities.SoftwareDetailActivity; +import net.oschina.app.improve.detail.activities.TranslateDetailActivity; +import net.oschina.app.improve.user.adapter.CollectionAdapter; +import net.oschina.app.improve.utils.DialogHelper; +import net.oschina.app.util.UIHelper; + +import java.lang.reflect.Type; + +import cz.msebera.android.httpclient.Header; + +/** + * Created by haibin + * on 2016/10/18. + */ + +public class UserCollectionActivity extends BaseRecyclerViewActivity implements BaseRecyclerAdapter.OnItemLongClickListener { + + public static void show(Context context) { + context.startActivity(new Intent(context, UserCollectionActivity.class)); + } + + @Override + protected void initWidget() { + super.initWidget(); + mAdapter.setOnItemLongClickListener(this); + } + + @Override + protected void onItemClick(Collection item, int position) { + switch (item.getType()) { + case News.TYPE_SOFTWARE: + SoftwareDetailActivity.show(this, item.getId()); + break; + case News.TYPE_QUESTION: + QuestionDetailActivity.show(this, item.getId()); + break; + case News.TYPE_BLOG: + BlogDetailActivity.show(this, item.getId()); + break; + case News.TYPE_TRANSLATE: + TranslateDetailActivity.show(this, item.getId()); + break; + case News.TYPE_EVENT: + EventDetailActivity.show(this, item.getId()); + break; + case News.TYPE_NEWS: + NewsDetailActivity.show(this, item.getId()); + break; + default: + UIHelper.showUrlRedirect(this, item.getHref()); + break; + } + } + + @Override + public void onLongClick(int position, long itemId) { + final Collection collection = mAdapter.getItem(position); + if (collection == null) + return; + DialogHelper.getConfirmDialog(this, "删除收藏", "是否确认删除该内容吗?", "确认", "取消", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + OSChinaApi.getFavReverse(collection.getId(), collection.getType(), new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + if (collection.isFavorite()) { + mAdapter.removeItem(collection); + } + } + }); + } + }).show(); + } + + @Override + protected void requestData() { + OSChinaApi.getCollectionList(mIsRefresh ? null : mBean.getNextPageToken(), mHandler); + } + + @Override + protected Type getType() { + return new TypeToken>>() { + }.getType(); + } + + @Override + protected BaseRecyclerAdapter getRecyclerAdapter() { + return new CollectionAdapter(this); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/user/activities/UserEventActivity.java b/app/src/main/java/net/oschina/app/improve/user/activities/UserEventActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..581b0e2e353e10f43dc04ecfe9a7a1ed11a79eb6 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/activities/UserEventActivity.java @@ -0,0 +1,68 @@ +package net.oschina.app.improve.user.activities; + +import android.content.Context; +import android.content.Intent; +import android.view.View; + +import net.oschina.app.R; +import net.oschina.app.improve.base.activities.BaseActivity; +import net.oschina.app.improve.user.fragments.UserEventFragment; +import net.oschina.app.util.UIHelper; + +import butterknife.OnClick; + +/** + * Created by fei + * on 2016/12/2. + * desc: + */ + +public class UserEventActivity extends BaseActivity implements View.OnClickListener { + + /** + * show the activity + * + * @param context context + */ + public static void show(Context context) { + Intent intent = new Intent(context, UserEventActivity.class); + context.startActivity(intent); + } + + @Override + protected int getContentView() { + return R.layout.activity_main_user_event; + } + + @Override + protected void initData() { + super.initData(); + + UserEventFragment userEventFragment = UserEventFragment.newInstance(); + + getSupportFragmentManager().beginTransaction().replace(R.id.lay_container, userEventFragment, + UserEventFragment.class.getName()).commitNowAllowingStateLoss(); + } + + @OnClick({R.id.tv_navigation_label, R.id.ib_event_scan}) + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.tv_navigation_label: + finish(); + break; + case R.id.ib_event_scan: + UIHelper.showScanActivity(this); + //finish(); + break; + default: + break; + } + } + + @Override + public void onBackPressed() { + super.onBackPressed(); + finish(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/user/activities/UserFansActivity.java b/app/src/main/java/net/oschina/app/improve/user/activities/UserFansActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..897d2caab27d4cb6ee9f646f51ba8c3d852b83aa --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/activities/UserFansActivity.java @@ -0,0 +1,92 @@ +package net.oschina.app.improve.user.activities; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; + +import com.google.gson.reflect.TypeToken; + +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.base.activities.BaseRecyclerViewActivity; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.bean.base.PageBean; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.notice.NoticeBean; +import net.oschina.app.improve.notice.NoticeManager; +import net.oschina.app.improve.user.adapter.UserFansOrFollowAdapter; +import net.oschina.app.improve.user.bean.UserFansOrFollows; + +import java.lang.reflect.Type; + +/** + * Created by fei on 2016/8/24. + * desc: user fans + */ + +public class UserFansActivity extends BaseRecyclerViewActivity { + + public static final String BUNDLE_KEY_ID = "bundle_key_id"; + private long userId; + + + private int getRequestType() { + return OSChinaApi.TYPE_USER_FANS; + } + + /** + * show activity + * + * @param context context + * @param userId uid + */ + public static void show(Context context, long userId) { + Intent intent = new Intent(context, UserFansActivity.class); + intent.putExtra(BUNDLE_KEY_ID, userId); + context.startActivity(intent); + } + + @Override + protected boolean initBundle(Bundle bundle) { + userId = bundle.getLong(BUNDLE_KEY_ID, 0); + return super.initBundle(bundle); + } + + @Override + protected void onResume() { + super.onResume(); + + NoticeBean FansNotice = NoticeManager.getNotice(); + if (FansNotice == null) return; + int fans = FansNotice.getFans(); + if (fans > 0) { + NoticeManager.clear(this, NoticeManager.FLAG_CLEAR_FANS); + } + + } + + + @Override + protected void requestData() { + super.requestData(); + OSChinaApi.getUserFansOrFlows(getRequestType(), userId, mIsRefresh ? null : mBean.getNextPageToken(), mHandler); + } + + @Override + protected Type getType() { + return new TypeToken>>() { + }.getType(); + } + + @Override + protected BaseRecyclerAdapter getRecyclerAdapter() { + return new UserFansOrFollowAdapter(this, BaseRecyclerAdapter.ONLY_FOOTER); + } + + @Override + protected void onItemClick(UserFansOrFollows item, int position) { + super.onItemClick(item, position); + if (item.getId() <= 0) return; + OtherUserHomeActivity.show(this, item.getId()); + } + +} diff --git a/app/src/main/java/net/oschina/app/improve/user/activities/UserFollowsActivity.java b/app/src/main/java/net/oschina/app/improve/user/activities/UserFollowsActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..3d90732b5ca441fb995351e70c46027a760e9b01 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/activities/UserFollowsActivity.java @@ -0,0 +1,77 @@ +package net.oschina.app.improve.user.activities; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; + +import com.google.gson.reflect.TypeToken; + +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.base.activities.BaseRecyclerViewActivity; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.bean.base.PageBean; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.user.adapter.UserFansOrFollowAdapter; +import net.oschina.app.improve.user.bean.UserFansOrFollows; + +import java.lang.reflect.Type; + +/** + * Created by fei on 2016/8/24. + * desc: user follows + */ + +public class UserFollowsActivity extends BaseRecyclerViewActivity { + + public static final String BUNDLE_KEY_ID = "bundle_key_id"; + // private static final String TAG = "UserFollowsActivity"; + private long userId; + + + private int getRequestType() { + return OSChinaApi.TYPE_USER_FOLOWS; + } + + /** + * show activity + * + * @param context context + * @param userId uid + */ + public static void show(Context context, long userId) { + Intent intent = new Intent(context, UserFollowsActivity.class); + intent.putExtra(BUNDLE_KEY_ID, userId); + context.startActivity(intent); + } + + @Override + protected boolean initBundle(Bundle bundle) { + userId = bundle.getLong(BUNDLE_KEY_ID, 0); + // TLog.e(TAG, "initBundle: ---------->userId=" + userId); + return super.initBundle(bundle); + } + + @Override + protected void requestData() { + super.requestData(); + OSChinaApi.getUserFansOrFlows(getRequestType(), userId, mIsRefresh ? null : mBean.getNextPageToken(), mHandler); + } + + @Override + protected Type getType() { + return new TypeToken>>() { + }.getType(); + } + + @Override + protected BaseRecyclerAdapter getRecyclerAdapter() { + return new UserFansOrFollowAdapter(this, BaseRecyclerAdapter.ONLY_FOOTER); + } + + @Override + protected void onItemClick(UserFansOrFollows item, int position) { + super.onItemClick(item, position); + if (item.getId() <= 0) return; + OtherUserHomeActivity.show(this, item.getId()); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/user/activities/UserMessageActivity.java b/app/src/main/java/net/oschina/app/improve/user/activities/UserMessageActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..f9aa838fa980ef227224898880d400f33cad718a --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/activities/UserMessageActivity.java @@ -0,0 +1,193 @@ +package net.oschina.app.improve.user.activities; + +import android.content.Context; +import android.content.Intent; +import android.support.design.widget.TabLayout; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentPagerAdapter; +import android.support.v4.view.ViewPager; + +import net.oschina.app.R; +import net.oschina.app.improve.base.activities.BaseBackActivity; +import net.oschina.app.improve.notice.NoticeBean; +import net.oschina.app.improve.notice.NoticeManager; +import net.oschina.app.improve.user.fragments.UserCommentFragment; +import net.oschina.app.improve.user.fragments.UserMentionFragment; +import net.oschina.app.improve.user.fragments.UserMessageFragment; + +import butterknife.Bind; + +/** + * Created by huanghaibin_dev + * Updated by Dominic Thanatosx + * on 2016/8/16. + */ +public class UserMessageActivity extends BaseBackActivity implements NoticeManager.NoticeNotify { + + @Bind(R.id.tabLayout) TabLayout mLayoutTab; + @Bind(R.id.vp_user_message) ViewPager mViewPager; + + private static final int INDEX_MENTION = 0; + private static final int INDEX_COMMENT = 1; + private static final int INDEX_MESSAGE = 2; + + private UserMentionFragment mUserMentionFragment; + private UserCommentFragment mUserCommentFragment; + private UserMessageFragment mUserMessageFragment; + + private NoticeBean mNotice; + + public static void show (Context context) { + + context.startActivity(new Intent(context, UserMessageActivity.class)); + } + + @Override + protected int getContentView () { + return R.layout.activity_user_message; + } + + @Override + protected void initWidget () { + super.initWidget(); + mNotice = NoticeManager.getNotice(); + + mUserMentionFragment = new UserMentionFragment(); + mUserCommentFragment = new UserCommentFragment(); + mUserMessageFragment = new UserMessageFragment(); + + NoticeManager.bindNotify(this); + + mLayoutTab.setupWithViewPager(mViewPager); + mViewPager.setAdapter(mAdapter); + mViewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { + @Override + public void onPageSelected (int position) { + clearSpecificNoticeIfNecessary(position); + } + }); + + final int mCurrentViewIndex = mNotice.getMention() > 0 + ? INDEX_MENTION + : mNotice.getReview() > 0 + ? INDEX_COMMENT + : mNotice.getLetter() > 0 + ? INDEX_MESSAGE + : INDEX_MENTION; + + mViewPager.setCurrentItem(mCurrentViewIndex); + clearSpecificNoticeIfNecessary(mCurrentViewIndex); + } + + private void clearSpecificNoticeIfNecessary(int position) { + switch (position) { + case INDEX_MENTION: + if (mNotice.getMention() <= 0) break; + clearSpecificNotice(position); + break; + case INDEX_COMMENT: + if (mNotice.getReview() <= 0) break; + clearSpecificNotice(position); + break; + case INDEX_MESSAGE: + if (mNotice.getLetter() <= 0) break; + clearSpecificNotice(position); + break; + } + } + + private void clearSpecificNotice(int position) { + switch (position) { + case INDEX_MENTION: + NoticeManager + .clear(getApplicationContext(), NoticeManager.FLAG_CLEAR_MENTION); + break; + case INDEX_COMMENT: + NoticeManager + .clear(getApplicationContext(), NoticeManager.FLAG_CLEAR_REVIEW); + break; + case INDEX_MESSAGE: + NoticeManager + .clear(getApplicationContext(), NoticeManager.FLAG_CLEAR_LETTER); + break; + } + } + + private void postChangeTitle (final int position, int delay) { + mViewPager.postDelayed(new Runnable() { + @Override + public void run () { + TabLayout.Tab tab = mLayoutTab.getTabAt(position); + if (tab == null) return; + tab.setText(mAdapter.getPageTitle(position)); + } + }, delay); + } + + public void onRequestSuccess (int position) { + if (mViewPager.getCurrentItem() != position) return; + clearSpecificNoticeIfNecessary(position); + } + + private void analyzeOldAndNew(int _old, int _new, int position) { + if (_old == _new) return; + if (mViewPager.getCurrentItem() != position || _new != 0) { + postChangeTitle(position, 0); + }else { + postChangeTitle(position, 1500); + } + } + + @Override + public void onNoticeArrived (NoticeBean bean) { + NoticeBean nb = mNotice; + mNotice = bean; + analyzeOldAndNew(nb.getMention(), bean.getMention(), INDEX_MENTION); + analyzeOldAndNew(nb.getReview(), bean.getReview(), INDEX_COMMENT); + analyzeOldAndNew(nb.getLetter(), bean.getLetter(), INDEX_MESSAGE); + } + + @Override + protected void onDestroy () { + super.onDestroy(); + NoticeManager.unBindNotify(this); + clearSpecificNotice(INDEX_MENTION); + clearSpecificNotice(INDEX_COMMENT); + clearSpecificNotice(INDEX_MESSAGE); + } + + private FragmentPagerAdapter mAdapter = new FragmentPagerAdapter(getSupportFragmentManager()) { + @Override + public Fragment getItem (int position) { + switch (position) { + case INDEX_MENTION: + return mUserMentionFragment; + case INDEX_COMMENT: + return mUserCommentFragment; + default: + return mUserMessageFragment; + } + } + + @Override + public int getCount () { + return 3; + } + + @Override + public CharSequence getPageTitle (int position) { + switch (position) { + case INDEX_MENTION: + return formatMessageCount("@我", mNotice.getMention()); + case INDEX_COMMENT: + return formatMessageCount("评论", mNotice.getReview()); + default: + return formatMessageCount("私信", mNotice.getLetter()); + } + } + }; + + private String formatMessageCount (String title, int messageCount) { + return messageCount == 0 ? title : String.format(title + "(%s)", messageCount); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/user/activities/UserSendMessageActivity.java b/app/src/main/java/net/oschina/app/improve/user/activities/UserSendMessageActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..771936f69aa9850f5e1e687f40deeceaddebdb94 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/activities/UserSendMessageActivity.java @@ -0,0 +1,277 @@ +package net.oschina.app.improve.user.activities; + + +import android.app.ProgressDialog; +import android.content.Context; +import android.content.Intent; +import android.support.design.widget.CoordinatorLayout; +import android.text.TextUtils; +import android.view.View; +import android.widget.EditText; +import android.widget.Toast; + +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.base.activities.BaseRecyclerViewActivity; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.bean.Message; +import net.oschina.app.improve.bean.User; +import net.oschina.app.improve.bean.base.PageBean; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.behavior.KeyboardInputDelegation; +import net.oschina.app.improve.media.ImageGalleryActivity; +import net.oschina.app.improve.media.SelectImageActivity; +import net.oschina.app.improve.media.config.SelectOptions; +import net.oschina.app.improve.user.adapter.UserSendMessageAdapter; +import net.oschina.app.improve.utils.PicturesCompressor; + +import java.io.File; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.Map; + +import butterknife.Bind; +import cz.msebera.android.httpclient.Header; + +/** + * 发送消息界面 + * Created by huanghaibin_dev + * on 2016/8/18. + */ +public class UserSendMessageActivity extends BaseRecyclerViewActivity { + + @Bind(R.id.root) + CoordinatorLayout mCoordinatorLayout; + private KeyboardInputDelegation mDelegation; + + EditText mViewInput; + private long authorId; + private User mReceiver; + private ProgressDialog mDialog; + private boolean isFirstLoading = true; + private Map mSendQuent = new HashMap<>(); + + public static void show(Context context, User sender) { + Intent intent = new Intent(context, UserSendMessageActivity.class); + intent.putExtra("receiver", sender); + context.startActivity(intent); + } + + @Override + protected int getContentView() { + return R.layout.activity_user_send_message; + } + + @Override + protected void initData() { + super.initData(); + mDialog = new ProgressDialog(this); + mReceiver = (User) getIntent().getSerializableExtra("receiver"); + setTitle(mReceiver.getName()); + authorId = AccountHelper.getUserId(); + init(); + } + + /** + * 下拉刷新为加载更多 + */ + @Override + public void onRefreshing() { + OSChinaApi.getMessageList(mReceiver.getId(), mBean.getNextPageToken(), mHandler); + } + + /** + * 去掉上拉加载 + */ + @Override + public void onLoadMore() { + + } + + protected void init() { + mDelegation = KeyboardInputDelegation.delegation(this, mCoordinatorLayout, null); + mDelegation.showEmoji(getSupportFragmentManager()); + mDelegation.showPic(new View.OnClickListener() { + @Override + public void onClick(View v) { + + SelectImageActivity.show(UserSendMessageActivity.this, new SelectOptions.Builder() + .setHasCam(true) + .setSelectCount(1) + .setCallback(new SelectOptions.Callback() { + @Override + public void doSelected(String[] images) { + final File file = new File(images[0]); + String path = file.getPath(); + if (mSendQuent.containsKey(getFileName(path))) { + Toast.makeText(UserSendMessageActivity.this, "图片已经在发送队列", Toast.LENGTH_SHORT).show(); + } else { + compress(path, new Run()); + } + } + }).build()); + } + }); + + mDelegation.setSendListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + String content = mDelegation.getInputText().replaceAll("[ \\s\\n]+", " "); + if (TextUtils.isEmpty(content)) { + Toast.makeText(UserSendMessageActivity.this, "请输入文字", Toast.LENGTH_SHORT).show(); + return; + } + mDialog.setMessage("正在发送中..."); + mDialog.show(); + OSChinaApi.pubMessage(mReceiver.getId(), content, new CallBack(null)); + } + }); + mViewInput = mDelegation.getInputView(); + } + + @Override + public void onItemClick(int position, long itemId) { + Message message = mAdapter.getItem(position); + if (Message.TYPE_IMAGE == message.getType()) { + if (message.getId() == 0) { + + } else if (message.getId() == -1) { //重新发送 + message.setId(0); + mAdapter.updateItem(position); + File file = new File(message.getResource()); + OSChinaApi.pubMessage(mReceiver.getId(), file, new CallBack(getFileName(file.getPath()))); + } else { + ImageGalleryActivity.show(this, message.getResource(), true, true); + } + } + } + + @Override + protected void setListData(ResultBean> resultBean) { + super.setListData(resultBean); + if (isFirstLoading) { + scrollToBottom(); + isFirstLoading = false; + } + + } + + private void scrollToBottom() { + mRecyclerView.scrollToPosition(mAdapter.getItems().size() - 1); + } + + @Override + protected Type getType() { + return new TypeToken>>() { + }.getType(); + } + + @Override + protected BaseRecyclerAdapter getRecyclerAdapter() { + return new UserSendMessageAdapter(this); + } + + private class CallBack extends TextHttpResponseHandler { + private String filePath; + + public CallBack(String filePath) { + this.filePath = filePath; + } + + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + if (filePath != null) { + Message message = mSendQuent.get(filePath); + message.setId(-1); + mAdapter.updateItem(mAdapter.getItems().indexOf(message)); + } + Toast.makeText(UserSendMessageActivity.this, "发送失败,请检查数据", Toast.LENGTH_SHORT).show(); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + Type type = new TypeToken>() { + }.getType(); + try { + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, type); + if (resultBean.isSuccess()) { + if (filePath != null) { + Message message = mSendQuent.get(filePath); + if (message != null) { + mAdapter.removeItem(message); + mSendQuent.remove(filePath); + delete(filePath); + } + } + mAdapter.addItem(resultBean.getResult()); + scrollToBottom(); + mViewInput.setText(""); + } else { + if (filePath != null) { + Message message = mSendQuent.get(filePath); + message.setId(-1); + mAdapter.updateItem(mAdapter.getItems().indexOf(message)); + } + Toast.makeText(UserSendMessageActivity.this, resultBean.getMessage(), Toast.LENGTH_SHORT).show(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void onFinish() { + super.onFinish(); + mDialog.dismiss(); + } + } + + private void compress(final String oriPath, final Run runnable) { + final String path = getFilesDir() + "/message/" + getFileName(oriPath); + AppOperator.runOnThread(new Runnable() { + @Override + public void run() { + if (PicturesCompressor.compressImage(oriPath, path, 512 * 1024)) { + runnable.setPath(path); + runOnUiThread(runnable); + } + } + }); + } + + private String getFileName(String filePath) { + return filePath.substring(filePath.lastIndexOf("/") + 1); + } + + private void delete(String path) { + File file = new File(path); + if (file.exists()) + file.delete(); + } + + private class Run implements Runnable { + private String path; + + @Override + public void run() { + File file = new File(path); + OSChinaApi.pubMessage(mReceiver.getId(), file, new CallBack(getFileName(path))); + Message message = new Message(); + message.setType(Message.TYPE_IMAGE); + message.setSender(AccountHelper.getUser()); + message.setResource(path); + mSendQuent.put(getFileName(path), message); + mAdapter.addItem(message); + scrollToBottom(); + } + + public void setPath(String path) { + this.path = path; + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/user/activities/UserTweetActivity.java b/app/src/main/java/net/oschina/app/improve/user/activities/UserTweetActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..939ca4743233aa84a2ff8159083546f5e942a67e --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/activities/UserTweetActivity.java @@ -0,0 +1,67 @@ +package net.oschina.app.improve.user.activities; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.app.Fragment; + +import net.oschina.app.R; +import net.oschina.app.improve.base.activities.BaseBackActivity; +import net.oschina.app.improve.tweet.fragments.TweetFragment; + +/** + * Created by fei on 2016/8/18. + * desc: + */ + +public class UserTweetActivity extends BaseBackActivity { + + private long uid; + private Fragment userTweetFragment; + + /** + * show activity + * + * @param context context + * @param uid uid + */ + public static void show(Context context, long uid) { + Intent intent = new Intent(context, UserTweetActivity.class); + intent.putExtra("uid", uid); + context.startActivity(intent); + } + + @Override + protected boolean initBundle(Bundle bundle) { + uid = bundle.getLong("uid", 0); + return uid > 0 || super.initBundle(bundle); + } + + @Override + protected int getContentView() { + return R.layout.activity_main_user_tweet; + } + + @Override + protected void initWidget() { + super.initWidget(); + if (userTweetFragment == null) + userTweetFragment = TweetFragment.instantiate(uid, 0); + getSupportFragmentManager().beginTransaction().add(R.id.user_tweet_container, userTweetFragment).commit(); + } + + + @Override + public void onBackPressed() { + super.onBackPressed(); + if (userTweetFragment != null) { + getSupportFragmentManager().beginTransaction().attach(userTweetFragment).commit(); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + finish(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/user/adapter/CollectionAdapter.java b/app/src/main/java/net/oschina/app/improve/user/adapter/CollectionAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..dd4f2b808e4d855f942680be6251fe4881ef14ab --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/adapter/CollectionAdapter.java @@ -0,0 +1,80 @@ +package net.oschina.app.improve.user.adapter; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import net.oschina.app.R; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.bean.Collection; +import net.oschina.app.improve.bean.News; +import net.oschina.app.improve.bean.User; +import net.oschina.app.util.StringUtils; + +/** + * Created by haibin + * on 2016/10/18. + */ + +public class CollectionAdapter extends BaseRecyclerAdapter { + public CollectionAdapter(Context context) { + super(context, ONLY_FOOTER); + } + + @Override + protected RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type) { + return new CollectionViewHolder(mInflater.inflate(R.layout.item_list_collection, parent, false)); + } + + @Override + protected void onBindDefaultViewHolder(RecyclerView.ViewHolder holder, Collection item, int position) { + CollectionViewHolder h = (CollectionViewHolder) holder; + String type = ""; + switch (item.getType()) { + case News.TYPE_SOFTWARE: + type = "软件"; + break; + case News.TYPE_QUESTION: + type = "问答"; + break; + case News.TYPE_BLOG: + type = "博客"; + break; + case News.TYPE_TRANSLATE: + type = "翻译"; + break; + case News.TYPE_EVENT: + type = "活动"; + break; + case News.TYPE_NEWS: + type = "资讯"; + break; + default: + type = "其他"; + break; + } + h.mTypeView.setText(type); + h.mTitleView.setText(item.getTitle()); + h.mFavDateText.setText(StringUtils.formatSomeAgo(item.getFavDate())); + User user = item.getAuthorUser(); + h.mAuthorText.setText(user != null ? user.getName() : "匿名"); + h.mCommentCountText.setText(String.valueOf(item.getCommentCount())); + h.mFavCountText.setText(String.valueOf(item.getFavCount())); + } + + private class CollectionViewHolder extends RecyclerView.ViewHolder { + private TextView mTypeView, mTitleView, mCommentCountText, mFavCountText, mAuthorText, mFavDateText; + + public CollectionViewHolder(View itemView) { + super(itemView); + mTypeView = (TextView) itemView.findViewById(R.id.tv_type); + mTitleView = (TextView) itemView.findViewById(R.id.tv_title); + mCommentCountText = (TextView) itemView.findViewById(R.id.tv_comment_count); + mFavCountText = (TextView) itemView.findViewById(R.id.tv_fav_count); + mAuthorText = (TextView) itemView.findViewById(R.id.tv_user); + mFavDateText = (TextView) itemView.findViewById(R.id.tv_fav_date); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/user/adapter/UserActiveAdapter.java b/app/src/main/java/net/oschina/app/improve/user/adapter/UserActiveAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..13133f9e3402e4781948eda8fe19beba8c4ce971 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/adapter/UserActiveAdapter.java @@ -0,0 +1,143 @@ +package net.oschina.app.improve.user.adapter; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.style.ForegroundColorSpan; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.bumptech.glide.RequestManager; + +import net.oschina.app.R; +import net.oschina.app.emoji.InputHelper; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.bean.Active; +import net.oschina.app.improve.bean.simple.Origin; +import net.oschina.app.improve.utils.AssimilateUtils; +import net.oschina.app.util.StringUtils; + +import butterknife.Bind; +import butterknife.ButterKnife; +import de.hdodenhof.circleimageview.CircleImageView; + +/** + * Created by thanatos on 16/7/14. + */ +public class UserActiveAdapter extends BaseRecyclerAdapter { + + private RequestManager mImageLoader; + + /** + * @param context Context + * @param rm Glide RequestManager should be related with fragment's liftcycle rather than Activity Context + */ + public UserActiveAdapter(Context context, RequestManager rm) { + super(context, ONLY_FOOTER); + mImageLoader = rm; + } + + @Override + protected RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type) { + return new ViewHolder(LayoutInflater.from(mContext).inflate(R.layout.list_item_active, parent, false)); + } + + @Override + protected void onBindDefaultViewHolder(RecyclerView.ViewHolder vh, Active item, int position) { + ViewHolder holder = (ViewHolder) vh; + + mImageLoader.load(item.getAuthor().getPortrait()) + .asBitmap() + .placeholder(R.mipmap.widget_dface) + .error(R.mipmap.widget_dface) + .into(holder.mViewPortrait); + + holder.mViewNick.setText(item.getAuthor().getName()); + holder.mViewTime.setText(StringUtils.formatSomeAgo(item.getPubDate())); + + Spannable spannable = AssimilateUtils.assimilateOnlyAtUser(mContext, item.getContent()); + spannable = AssimilateUtils.assimilateOnlyTag(mContext, spannable); + spannable = AssimilateUtils.assimilateOnlyLink(mContext, spannable); + spannable = InputHelper.displayEmoji(mContext.getResources(), spannable); + holder.mViewContent.setText(spannable); + + holder.mViewTitle.setText(getWhichTitle(item.getOrigin())); + + if (item.getOrigin().getType() == Origin.ORIGIN_TYPE_TWEETS) { + holder.mViewReply.setVisibility(View.VISIBLE); + holder.mViewReply.setText(item.getOrigin().getDesc()); + } else { + holder.mViewReply.setVisibility(View.GONE); + } + + } + + private CharSequence getWhichTitle(Origin origin) { + if (origin == null) return "更新了动态"; + String desc = "评论了%s%s:"; + String which; + String title = "“" + origin.getDesc() + "”"; + switch (origin.getType()) { + case Origin.ORIGIN_TYPE_LINK: + which = "新闻"; + break; + case Origin.ORIGIN_TYPE_SOFTWARE: + which = "软件推荐"; + break; + case Origin.ORIGIN_TYPE_DISCUSS: + which = "帖子"; + break; + case Origin.ORIGIN_TYPE_BLOG: + which = "博客"; + break; + case Origin.ORIGIN_TYPE_TRANSLATION: + which = "翻译文章"; + break; + case Origin.ORIGIN_TYPE_ACTIVE: + which = "活动"; + break; + case Origin.ORIGIN_TYPE_NEWS: + which = "资讯"; + break; + case Origin.ORIGIN_TYPE_TWEETS: + which = "动弹"; + title = ""; + break; + default: + which = "文章"; + title = ""; + } + desc = String.format(desc, which, title); + if (title.length() == 0) return desc; + SpannableStringBuilder builder = new SpannableStringBuilder(desc); + int start = which.length() + 4; + int end = start + title.length() - 2; + ForegroundColorSpan cs = new ForegroundColorSpan(mContext.getResources().getColor(R.color.day_colorPrimary)); + builder.setSpan(cs, start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + return builder; + } + + static class ViewHolder extends RecyclerView.ViewHolder { + @Bind(R.id.tv_nick) + TextView mViewNick; + @Bind(R.id.tv_time) + TextView mViewTime; + @Bind(R.id.tv_title) + TextView mViewTitle; + @Bind(R.id.tv_reply) + TextView mViewReply; + @Bind(R.id.tv_content) + TextView mViewContent; + @Bind(R.id.iv_portrait) + CircleImageView mViewPortrait; + + public ViewHolder(View view) { + super(view); + ButterKnife.bind(this, view); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/user/adapter/UserBlogAdapter.java b/app/src/main/java/net/oschina/app/improve/user/adapter/UserBlogAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..5d8285e4f715ab9224d5351ae65237481a2c47c3 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/adapter/UserBlogAdapter.java @@ -0,0 +1,85 @@ +package net.oschina.app.improve.user.adapter; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.support.v7.widget.RecyclerView; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.style.ImageSpan; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import net.oschina.app.R; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.bean.Blog; +import net.oschina.app.util.StringUtils; + +import butterknife.Bind; +import butterknife.ButterKnife; + +/** + * Created by thanatos on 16/8/17. + */ +public class UserBlogAdapter extends BaseRecyclerAdapter { + + public UserBlogAdapter(Context context, int mode) { + super(context, mode); + } + + @Override + protected RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type) { + return new ViewHolder(LayoutInflater.from(mContext).inflate(R.layout.fragment_item_blog, parent, false)); + } + + @SuppressWarnings("all") + @Override + protected void onBindDefaultViewHolder(RecyclerView.ViewHolder h, Blog item, int position) { + ViewHolder holder = (ViewHolder) h; + + SpannableStringBuilder builder = new SpannableStringBuilder(); + if (item.isOriginal()) { + builder.append("[icon] "); + Drawable originate = mContext.getResources().getDrawable(R.mipmap.ic_label_originate); + originate.setBounds(0, 0, originate.getIntrinsicWidth(), originate.getIntrinsicHeight()); + ImageSpan imageSpan = new ImageSpan(originate, ImageSpan.ALIGN_BOTTOM); + builder.setSpan(imageSpan, 0, 6, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + } + if (item.isRecommend()) { + int start = builder.length(); + builder.append("[icon] "); + Drawable originate = mContext.getResources().getDrawable(R.mipmap.ic_label_recommend); + originate.setBounds(0, 0, originate.getIntrinsicWidth(), originate.getIntrinsicHeight()); + ImageSpan imageSpan = new ImageSpan(originate, ImageSpan.ALIGN_BOTTOM); + builder.setSpan(imageSpan, start, start + 6, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + } + builder.append(item.getTitle()); + holder.mViewTitle.setText(builder); + + holder.mViewContent.setText(item.getBody()); + String nick = item.getAuthor(); + holder.mViewHistory.setText(nick.length() > 9 ? nick.substring(0, 9) : nick + " " + StringUtils.formatSomeAgo(item.getPubDate())); + holder.mViewInfoCmm.setText(String.valueOf(item.getCommentCount())); + holder.mViewInfoVisual.setText(String.valueOf(item.getViewCount())); + + } + + public static class ViewHolder extends RecyclerView.ViewHolder { + @Bind(R.id.tv_item_blog_title) + TextView mViewTitle; + @Bind(R.id.tv_item_blog_body) + TextView mViewContent; + @Bind(R.id.tv_item_blog_history) + TextView mViewHistory; + @Bind(R.id.tv_info_view) + TextView mViewInfoVisual; + @Bind(R.id.tv_info_comment) + TextView mViewInfoCmm; + + public ViewHolder(View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/user/adapter/UserEventAdapter.java b/app/src/main/java/net/oschina/app/improve/user/adapter/UserEventAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..4defac4476efd8d7e17c09acd4cd0fb7211c5d6c --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/adapter/UserEventAdapter.java @@ -0,0 +1,140 @@ +package net.oschina.app.improve.user.adapter; + +import android.annotation.SuppressLint; +import android.content.res.Resources; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import net.oschina.app.OSCApplication; +import net.oschina.app.R; +import net.oschina.app.improve.base.adapter.BaseGeneralRecyclerAdapter; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.bean.Event; +import net.oschina.app.improve.bean.SubBean; +import net.oschina.app.util.StringUtils; +import net.qiujuer.genius.ui.compat.UiCompat; + +import java.util.Map; + +/** + * Created by fei + * on 2016/12/2. + * desc: + */ + +public class UserEventAdapter extends BaseGeneralRecyclerAdapter implements BaseRecyclerAdapter.OnLoadingHeaderCallBack { + + private OSCApplication.ReadState mReadState; + + public UserEventAdapter(Callback callback, int mode) { + super(callback, mode); + mReadState = OSCApplication.getReadState("sub_list"); + setOnLoadingHeaderCallBack(this); + } + + @Override + public RecyclerView.ViewHolder onCreateHeaderHolder(ViewGroup parent) { + return new HeaderViewHolder(mHeaderView); + } + + @Override + public void onBindHeaderHolder(RecyclerView.ViewHolder holder, int position) { + + } + + @Override + protected RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type) { + return new EventViewHolder(mInflater.inflate(R.layout.item_list_sub_event, parent, false)); + } + + @SuppressLint("SetTextI18n") + @Override + protected void onBindDefaultViewHolder(RecyclerView.ViewHolder holder, SubBean item, int position) { + EventViewHolder vh = (EventViewHolder) holder; + vh.tv_event_title.setText(item.getTitle()); + SubBean.Image image = item.getImage(); + if (image != null) { + mCallBack.getImgLoader() + .load(image.getHref() != null && image.getHref().length > 0 ? image.getHref()[0] : null) + .placeholder(R.drawable.bg_normal) + .into(vh.iv_event); + } else { + vh.iv_event.setImageResource(R.drawable.bg_normal); + } + + Resources resources = mContext.getResources(); + + Map extras = item.getExtra(); + if (extras != null) { + vh.tv_event_pub_date.setText(StringUtils.getDateString(extras.get("eventStartDate").toString())); + vh.tv_event_member.setText(Double.valueOf(extras.get("eventApplyCount").toString()).intValue() + "人参与"); + + switch (Double.valueOf(extras.get("eventStatus").toString()).intValue()) { + case Event.STATUS_END: + setText(vh.tv_event_state, R.string.event_status_end, R.drawable.bg_event_end, 0x1a000000); + setTextColor(vh.tv_event_title, UiCompat.getColor(resources, R.color.light_gray)); + break; + case Event.STATUS_ING: + setText(vh.tv_event_state, R.string.event_status_ing, R.drawable.bg_event_ing, 0xFF24cf5f); + break; + case Event.STATUS_SING_UP: + setText(vh.tv_event_state, R.string.event_status_sing_up, R.drawable.bg_event_end, 0x1a000000); + setTextColor(vh.tv_event_title, UiCompat.getColor(resources, R.color.light_gray)); + break; + } + int typeStr = R.string.oscsite; + switch (Double.valueOf(extras.get("eventType").toString()).intValue()) { + case Event.EVENT_TYPE_OSC: + typeStr = R.string.event_type_osc; + break; + case Event.EVENT_TYPE_TEC: + typeStr = R.string.event_type_tec; + break; + case Event.EVENT_TYPE_OTHER: + typeStr = R.string.event_type_other; + break; + case Event.EVENT_TYPE_OUTSIDE: + typeStr = R.string.event_type_outside; + break; + } + vh.tv_event_type.setText(typeStr); + } + + vh.tv_event_title.setTextColor(UiCompat.getColor(resources, + mReadState.already(item.getKey()) + ? R.color.text_desc_color : R.color.text_title_color)); + + } + + private void setText(TextView tv, int textRes, int bgRes, int textColor) { + tv.setText(textRes); + tv.setVisibility(View.VISIBLE); + tv.setBackgroundResource(bgRes); + tv.setTextColor(textColor); + } + + private void setTextColor(TextView tv, int textColor) { + tv.setTextColor(textColor); + tv.setVisibility(View.VISIBLE); + } + + private static class EventViewHolder extends RecyclerView.ViewHolder { + TextView tv_event_title, tv_description, tv_event_pub_date, tv_event_member, tv_event_state, tv_event_type; + ImageView iv_event; + + public EventViewHolder(View itemView) { + super(itemView); + tv_event_title = (TextView) itemView.findViewById(R.id.tv_event_title); + tv_event_state = (TextView) itemView.findViewById(R.id.tv_event_state); + tv_event_type = (TextView) itemView.findViewById(R.id.tv_event_type); + tv_description = (TextView) itemView.findViewById(R.id.tv_description); + tv_event_pub_date = (TextView) itemView.findViewById(R.id.tv_event_pub_date); + tv_event_member = (TextView) itemView.findViewById(R.id.tv_event_member); + iv_event = (ImageView) itemView.findViewById(R.id.iv_event); + } + } + +} diff --git a/app/src/main/java/net/oschina/app/improve/user/adapter/UserFansOrFollowAdapter.java b/app/src/main/java/net/oschina/app/improve/user/adapter/UserFansOrFollowAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..3327d20c423214ef1af6bc64eb86bed39e7e3dfb --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/adapter/UserFansOrFollowAdapter.java @@ -0,0 +1,101 @@ +package net.oschina.app.improve.user.adapter; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.RequestManager; + +import net.oschina.app.R; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.user.bean.UserFansOrFollows; +import net.oschina.app.util.ImageLoader; + +import butterknife.Bind; +import butterknife.ButterKnife; +import de.hdodenhof.circleimageview.CircleImageView; + +/** + * Created by fei on 2016/8/24. + * desc: + */ + +public class UserFansOrFollowAdapter extends BaseRecyclerAdapter { + + //private static final String TAG = "UserFansOrFollowAdapter"; + private RequestManager requestManager; + + public UserFansOrFollowAdapter(Context context, int mode) { + super(context, mode); + requestManager = Glide.with(context); + } + + @Override + protected RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type) { + return new UserFansViewHolder(mInflater.inflate(R.layout.activity_item_user_flow, parent, false)); + } + + @Override + protected void onBindDefaultViewHolder(RecyclerView.ViewHolder holder, UserFansOrFollows item, int position) { + + if (item == null) return; + final UserFansViewHolder vh = (UserFansViewHolder) holder; + ImageLoader.loadImage(requestManager, vh.mCiIcon, item.getPortrait(), R.mipmap.widget_dface); + vh.mTvName.setText(item.getName()); + switch (item.getGender()) { + case 0: + vh.mIvSex.setVisibility(View.GONE); + break; + case 1: + vh.mIvSex.setVisibility(View.VISIBLE); + vh.mIvSex.setImageResource(R.mipmap.userinfo_icon_male); + break; + case 2: + vh.mIvSex.setVisibility(View.VISIBLE); + vh.mIvSex.setImageResource(R.mipmap.userinfo_icon_female); + break; + default: + break; + } + vh.mTvDesc.setText(item.getDesc()); + UserFansOrFollows.More more = item.getMore(); + if (more == null) return; + vh.mTvCity.setText(more.getCity()); + vh.mTvExp.setText(more.getExpertise()); + + } + + @Override + public void setOnItemClickListener(OnItemClickListener onItemClickListener) { + super.setOnItemClickListener(onItemClickListener); + } + + /** + * + */ + class UserFansViewHolder extends RecyclerView.ViewHolder { + + @Bind(R.id.iv_user_flow_icon) + CircleImageView mCiIcon; + @Bind(R.id.tv_user_flow_name) + TextView mTvName; + @Bind(R.id.iv_user_flow_sex) + ImageView mIvSex; + @Bind(R.id.tv_user_flow_city) + TextView mTvCity; + @Bind(R.id.tv_user_flow_desc) + TextView mTvDesc; + @Bind(R.id.tv_user_flow_expertise) + TextView mTvExp; + + + UserFansViewHolder(View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/user/adapter/UserFavoritesAdapter.java b/app/src/main/java/net/oschina/app/improve/user/adapter/UserFavoritesAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..4addfd83cf8e963d548fcc3de4989ab4050f7e00 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/adapter/UserFavoritesAdapter.java @@ -0,0 +1,49 @@ +package net.oschina.app.improve.user.adapter; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import net.oschina.app.R; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.user.bean.UserFavorites; + +import butterknife.Bind; +import butterknife.ButterKnife; + +/** + * Created by fei on 2016/8/30. + * desc: + */ + +public class UserFavoritesAdapter extends BaseRecyclerAdapter { + + public UserFavoritesAdapter(Context context, int mode) { + super(context, mode); + } + + @Override + protected RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type) { + View view = mInflater.inflate(R.layout.list_cell_favorite, parent, false); + return new ViewHolder(view); + } + + @Override + protected void onBindDefaultViewHolder(RecyclerView.ViewHolder holder, UserFavorites item, int position) { + ViewHolder vh = (ViewHolder) holder; + vh.tvTitle.setText(item.getTitle()); + } + + static class ViewHolder extends RecyclerView.ViewHolder { + + @Bind(R.id.tv_favorite_title) + TextView tvTitle; + + public ViewHolder(View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/user/adapter/UserMentionAdapter.java b/app/src/main/java/net/oschina/app/improve/user/adapter/UserMentionAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..6278b356f47d00596242972b305c9bb404cc8c8a --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/adapter/UserMentionAdapter.java @@ -0,0 +1,101 @@ +package net.oschina.app.improve.user.adapter; + +import android.support.v7.widget.RecyclerView; +import android.text.TextUtils; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import net.oschina.app.R; +import net.oschina.app.improve.base.adapter.BaseGeneralRecyclerAdapter; +import net.oschina.app.improve.bean.Mention; +import net.oschina.app.improve.bean.simple.Author; +import net.oschina.app.improve.bean.simple.Origin; +import net.oschina.app.improve.user.activities.OtherUserHomeActivity; +import net.oschina.app.util.PlatfromUtil; +import net.oschina.app.util.StringUtils; +import net.oschina.app.widget.TweetTextView; + +import de.hdodenhof.circleimageview.CircleImageView; + +/** + * Created by huanghaibin_dev + * on 2016/8/16. + */ + +public class UserMentionAdapter extends BaseGeneralRecyclerAdapter { + private OnUserFaceClickListener mListener; + + public UserMentionAdapter(Callback callback) { + super(callback, ONLY_FOOTER); + initListener(); + } + + private void initListener() { + mListener = new UserMentionAdapter.OnUserFaceClickListener() { + @Override + public void onClick(View v, int position) { + Author author = getItem(position).getAuthor(); + if (author != null) + OtherUserHomeActivity.show(mCallBack.getContext(), author.getId()); + } + }; + } + + @Override + protected RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type) { + MentionViewHolder holder = new UserMentionAdapter.MentionViewHolder(mInflater.inflate(R.layout.item_list_comment, parent, false)); + holder.iv_user_avatar.setTag(R.id.iv_face, holder); + return holder; + } + + @Override + protected void onBindDefaultViewHolder(RecyclerView.ViewHolder holder, Mention item, int position) { + MentionViewHolder viewHolder = (MentionViewHolder) holder; + Author author = item.getAuthor(); + if (author != null) { + mCallBack.getImgLoader().load(author.getPortrait()).asBitmap().placeholder(R.mipmap.widget_dface).into(viewHolder.iv_user_avatar); + viewHolder.tv_user_name.setText(author.getName()); + } + viewHolder.iv_user_avatar.setOnClickListener(mListener); + PlatfromUtil.setPlatFromString(viewHolder.tv_platform, item.getAppClient()); + viewHolder.tv_comment_count.setText(String.valueOf(item.getCommentCount())); + viewHolder.tv_time.setText(StringUtils.formatSomeAgo(item.getPubDate())); + parseAtUserContent(viewHolder.tv_content, item.getContent()); + Origin origin = item.getOrigin(); + if (origin != null && !TextUtils.isEmpty(origin.getDesc())) { + viewHolder.tv_origin.setVisibility(View.VISIBLE); + parseAtUserContent(viewHolder.tv_origin, item.getOrigin().getDesc()); + } else { + viewHolder.tv_origin.setVisibility(View.GONE); + } + + } + + private static class MentionViewHolder extends RecyclerView.ViewHolder { + CircleImageView iv_user_avatar; + TextView tv_user_name, tv_time, tv_platform, tv_comment_count; + TweetTextView tv_content, tv_origin; + + public MentionViewHolder(View itemView) { + super(itemView); + iv_user_avatar = (CircleImageView) itemView.findViewById(R.id.iv_user_avatar); + tv_user_name = (TextView) itemView.findViewById(R.id.tv_user_name); + tv_time = (TextView) itemView.findViewById(R.id.tv_time); + tv_content = (TweetTextView) itemView.findViewById(R.id.tv_content); + tv_origin = (TweetTextView) itemView.findViewById(R.id.tv_origin); + tv_platform = (TextView) itemView.findViewById(R.id.tv_platform); + tv_comment_count = (TextView) itemView.findViewById(R.id.tv_comment_count); + } + } + + private abstract class OnUserFaceClickListener implements View.OnClickListener { + @Override + public void onClick(View v) { + MentionViewHolder holder = (MentionViewHolder) v.getTag(R.id.iv_face); + onClick(v, holder.getAdapterPosition()); + } + + public abstract void onClick(View v, int position); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/user/adapter/UserMessageAdapter.java b/app/src/main/java/net/oschina/app/improve/user/adapter/UserMessageAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..82efddedcb866b421065726c414f48db568790f7 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/adapter/UserMessageAdapter.java @@ -0,0 +1,97 @@ +package net.oschina.app.improve.user.adapter; + +import android.support.v7.widget.RecyclerView; +import android.text.TextUtils; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import net.oschina.app.R; +import net.oschina.app.emoji.InputHelper; +import net.oschina.app.improve.base.adapter.BaseGeneralRecyclerAdapter; +import net.oschina.app.improve.bean.Message; +import net.oschina.app.improve.bean.User; +import net.oschina.app.improve.user.activities.OtherUserHomeActivity; +import net.oschina.app.util.StringUtils; + +import de.hdodenhof.circleimageview.CircleImageView; + +/** + * Created by huanghaibin_dev + * on 2016/8/16. + */ + +public class UserMessageAdapter extends BaseGeneralRecyclerAdapter { + private OnUserFaceClickListener mListener; + + public UserMessageAdapter(Callback callback) { + super(callback, ONLY_FOOTER); + initListener(); + } + + private void initListener() { + mListener = new OnUserFaceClickListener() { + @Override + public void onClick(View v, int position) { + User author = getItem(position).getSender(); + if (author != null) + OtherUserHomeActivity.show(mCallBack.getContext(), author.getId()); + } + }; + } + + @Override + protected RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type) { + MessageViewHolder holder = new MessageViewHolder(mInflater.inflate(R.layout.item_list_message, parent, false)); + holder.iv_user_avatar.setTag(R.id.iv_face, holder); + return holder; + } + + @Override + protected void onBindDefaultViewHolder(RecyclerView.ViewHolder holder, Message item, int position) { + MessageViewHolder messageViewHolder = (MessageViewHolder) holder; + User author = item.getSender(); + if (author != null) { + mCallBack.getImgLoader().load(author.getPortrait()).asBitmap().placeholder(R.mipmap.widget_dface).into(messageViewHolder.iv_user_avatar); + messageViewHolder.tv_user_name.setText(author.getName()); + } + messageViewHolder.iv_user_avatar.setOnClickListener(mListener); + parseAtUserContent(messageViewHolder.tv_content, item.getContent()); + messageViewHolder.tv_time.setText(StringUtils.formatSomeAgo(item.getPubDate())); + } + + + protected void parseAtUserContent(TextView textView, String text) { + String content = ""; + if (TextUtils.isEmpty(text)) { + textView.setText("[图片]"); + return; + } + content = text.replaceAll("[\n\\s]+", " ").replaceAll("<[^<>]+>([^<>]*)]+>", "$1"); + textView.setText(InputHelper.displayEmoji(mCallBack.getContext().getResources(), content)); + } + + private static class MessageViewHolder extends RecyclerView.ViewHolder { + CircleImageView iv_user_avatar; + TextView tv_user_name, tv_time; + TextView tv_content; + + public MessageViewHolder(View itemView) { + super(itemView); + iv_user_avatar = (CircleImageView) itemView.findViewById(R.id.iv_user_avatar); + tv_user_name = (TextView) itemView.findViewById(R.id.tv_user_name); + tv_time = (TextView) itemView.findViewById(R.id.tv_time); + tv_content = (TextView) itemView.findViewById(R.id.tv_content); + } + } + + private abstract class OnUserFaceClickListener implements View.OnClickListener { + @Override + public void onClick(View v) { + MessageViewHolder holder = (MessageViewHolder) v.getTag(R.id.iv_face); + onClick(v, holder.getAdapterPosition()); + } + + public abstract void onClick(View v, int position); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/user/adapter/UserQuestionAdapter.java b/app/src/main/java/net/oschina/app/improve/user/adapter/UserQuestionAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..01782449dc3085edaf342c6118b5059474fda728 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/adapter/UserQuestionAdapter.java @@ -0,0 +1,73 @@ +package net.oschina.app.improve.user.adapter; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.bumptech.glide.Glide; + +import net.oschina.app.R; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.bean.Question; +import net.oschina.app.util.StringUtils; + +import butterknife.Bind; +import butterknife.ButterKnife; +import de.hdodenhof.circleimageview.CircleImageView; + +/** + * Created by thanatos on 16/8/17. + */ +public class UserQuestionAdapter extends BaseRecyclerAdapter { + + public UserQuestionAdapter(Context context, int mode) { + super(context, mode); + } + + @Override + protected RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type) { + return new ViewHolder(LayoutInflater.from(mContext).inflate(R.layout.fragment_item_question, parent, false)); + } + + @Override + protected void onBindDefaultViewHolder(RecyclerView.ViewHolder h, Question item, int position) { + ViewHolder holder = (ViewHolder) h; + Glide.with(mContext) + .load(item.getAuthorPortrait()) + .asBitmap() + .placeholder(R.mipmap.widget_dface) + .error(R.mipmap.widget_dface) + .into(holder.mViewPortrait); + holder.mViewTitle.setText(item.getTitle()); + holder.mViewContent.setText(item.getBody()); + String nick = item.getAuthor(); + holder.mViewHistory.setText(nick.length() > 9 + ? nick.substring(0, 9) + : nick + " " + StringUtils.formatSomeAgo(item.getPubDate())); + holder.mViewInfoCmm.setText(String.valueOf(item.getCommentCount())); + holder.mViewInfoVisual.setText(String.valueOf(item.getViewCount())); + } + + public static class ViewHolder extends RecyclerView.ViewHolder { + @Bind(R.id.iv_ques_item_icon) + CircleImageView mViewPortrait; + @Bind(R.id.tv_ques_item_title) + TextView mViewTitle; + @Bind(R.id.tv_ques_item_content) + TextView mViewContent; + @Bind(R.id.tv_ques_item_history) + TextView mViewHistory; + @Bind(R.id.tv_info_view) + TextView mViewInfoVisual; + @Bind(R.id.tv_info_comment) + TextView mViewInfoCmm; + + public ViewHolder(View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/user/adapter/UserSendMessageAdapter.java b/app/src/main/java/net/oschina/app/improve/user/adapter/UserSendMessageAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..1633c5fa4075ff7cb2479648ef5b34ce149cda70 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/adapter/UserSendMessageAdapter.java @@ -0,0 +1,281 @@ +package net.oschina.app.improve.user.adapter; + +import android.support.v7.widget.RecyclerView; +import android.text.TextUtils; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.load.engine.DiskCacheStrategy; +import com.bumptech.glide.load.model.GlideUrl; +import com.bumptech.glide.load.resource.drawable.GlideDrawable; +import com.bumptech.glide.request.RequestListener; +import com.bumptech.glide.request.target.Target; + +import net.oschina.app.R; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.base.adapter.BaseGeneralRecyclerAdapter; +import net.oschina.app.improve.bean.Message; +import net.oschina.app.util.StringUtils; +import net.oschina.app.widget.TweetTextView; +import net.qiujuer.genius.ui.widget.Loading; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +/** + * Created by huanghaibin_dev + * on 2016/8/18. + */ +public class UserSendMessageAdapter extends BaseGeneralRecyclerAdapter { + private static final int SENDER = 1; + private static final int SENDER_PICTURE = 2; + private static final int RECEIVER = 3; + private static final int RECEIVER_PICTURE = 4; + private long authorId; + + public UserSendMessageAdapter(Callback callback) { + super(callback, NEITHER); + authorId = AccountHelper.getUserId(); + } + + @Override + public int getItemViewType(int position) { + Message item = getItem(position); + if (item.getSender().getId() == authorId) {//如果是个人发送的私信 + if (Message.TYPE_IMAGE == item.getType()) + return SENDER_PICTURE; + return SENDER; + } else { + if (Message.TYPE_IMAGE == item.getType()) + return RECEIVER_PICTURE; + return RECEIVER; + } + } + + public ImageView getTargetImageView(int position, RecyclerView recyclerView) { + RecyclerView.ViewHolder holder = recyclerView.findViewHolderForAdapterPosition(position); + if (holder != null) { + if (holder instanceof SenderPictureViewHolder) + return ((SenderPictureViewHolder) holder).iv_sender_picture; + if (holder instanceof ReceiverPictureViewHolder) + return ((ReceiverPictureViewHolder) holder).iv_receiver_picture; + } + return null; + } + + @Override + protected RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type) { + if (type == SENDER) + return new SenderViewHolder(mInflater.inflate(R.layout.item_list_user_send_message, parent, false)); + else if (type == SENDER_PICTURE) + return new SenderPictureViewHolder(mInflater.inflate(R.layout.item_list_user_send_message_picture, parent, false)); + else if (type == RECEIVER) + return new ReceiverViewHolder(mInflater.inflate(R.layout.item_list_receiver_message, parent, false)); + else + return new ReceiverPictureViewHolder(mInflater.inflate(R.layout.item_list_receiver_message_picture, parent, false)); + } + + @Override + protected void onBindDefaultViewHolder(RecyclerView.ViewHolder holder, final Message item, int position) { + Message preMessage = position != 0 ? getItem(position - 1) : null; + switch (getItemViewType(position)) { + case SENDER: + SenderViewHolder senderViewHolder = (SenderViewHolder) holder; + parseAtUserContent(senderViewHolder.tv_sender, item.getContent()); + formatTime(preMessage, item, senderViewHolder.tv_send_time); + break; + case SENDER_PICTURE: + final SenderPictureViewHolder senderPictureViewHolder = (SenderPictureViewHolder) holder; + if (item.getId() == 0) { + mCallBack.getImgLoader() + .load(item.getResource()) + .diskCacheStrategy(DiskCacheStrategy.ALL) + .error(R.mipmap.ic_split_graph) + .into(senderPictureViewHolder.iv_sender_picture); + senderPictureViewHolder.loading.setVisibility(View.VISIBLE); + senderPictureViewHolder.loading.start(); + senderPictureViewHolder.iv_resend.setVisibility(View.INVISIBLE); + } else if (item.getId() == -1) { + mCallBack.getImgLoader() + .load(item.getResource()) + .diskCacheStrategy(DiskCacheStrategy.ALL) + .error(R.mipmap.ic_split_graph) + .into(senderPictureViewHolder.iv_sender_picture); + senderPictureViewHolder.loading.setVisibility(View.GONE); + senderPictureViewHolder.loading.stop(); + senderPictureViewHolder.iv_resend.setVisibility(View.VISIBLE); + } else { + senderPictureViewHolder.loading.setVisibility(View.VISIBLE); + senderPictureViewHolder.loading.start(); + senderPictureViewHolder.iv_resend.setVisibility(View.INVISIBLE); + Glide.clear(senderPictureViewHolder.iv_sender_picture); + mCallBack.getImgLoader() + .load(AppOperator.getGlideUrlByUser(item.getResource())) + .listener(new RequestListener() { + @Override + public boolean onException(Exception e, GlideUrl model, Target target, boolean isFirstResource) { + senderPictureViewHolder.loading.setVisibility(View.GONE); + senderPictureViewHolder.loading.stop(); + return false; + } + + @Override + public boolean onResourceReady(GlideDrawable resource, GlideUrl model, Target target, boolean isFromMemoryCache, boolean isFirstResource) { + senderPictureViewHolder.loading.setVisibility(View.GONE); + senderPictureViewHolder.loading.stop(); + return false; + } + }) + .placeholder(R.color.list_divider_color) + .error(R.mipmap.ic_split_graph) + .into(senderPictureViewHolder.iv_sender_picture); + + } + formatTime(preMessage, item, senderPictureViewHolder.tv_send_time); + break; + case RECEIVER: + ReceiverViewHolder receiverViewHolder = (ReceiverViewHolder) holder; + parseAtUserContent(receiverViewHolder.tv_receiver, item.getContent()); + formatTime(preMessage, item, receiverViewHolder.tv_send_time); + break; + case RECEIVER_PICTURE: + final ReceiverPictureViewHolder receiverPictureViewHolder = (ReceiverPictureViewHolder) holder; + receiverPictureViewHolder.loading.setVisibility(View.VISIBLE); + receiverPictureViewHolder.loading.start(); + mCallBack.getImgLoader() + .load(AppOperator.getGlideUrlByUser(item.getResource())) + .listener(new RequestListener() { + @Override + public boolean onException(Exception e, GlideUrl model, Target target, boolean isFirstResource) { + receiverPictureViewHolder.loading.setVisibility(View.GONE); + receiverPictureViewHolder.loading.stop(); + return false; + } + + @Override + public boolean onResourceReady(GlideDrawable resource, GlideUrl model, Target target, boolean isFromMemoryCache, boolean isFirstResource) { + receiverPictureViewHolder.loading.setVisibility(View.GONE); + receiverPictureViewHolder.loading.stop(); + return false; + } + }) + .placeholder(R.color.list_divider_color) + .error(R.mipmap.ic_split_graph) + .into(receiverPictureViewHolder.iv_receiver_picture); + formatTime(preMessage, item, receiverPictureViewHolder.tv_send_time); + break; + } + } + + + private void formatTime(Message preMessage, Message item, TextView tv_time) { + tv_time.setVisibility(View.GONE); + if (preMessage == null) { + formatTime(tv_time, item.getPubDate()); + tv_time.setVisibility(View.VISIBLE); + } else { + if (checkTime(preMessage.getPubDate(), item.getPubDate())) { + formatTime(tv_time, item.getPubDate()); + tv_time.setVisibility(View.VISIBLE); + } + } + } + + private boolean checkTime(String firstTime, String secondTime) { + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); + try { + long first = format.parse(firstTime).getTime(); + long second = format.parse(secondTime).getTime(); + return second - first > 300000; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + private String formatWeek(Date date) { + SimpleDateFormat format = new SimpleDateFormat("EEEE"); + return format.format(date); + } + + private String formatDate(Date date) { + SimpleDateFormat format = new SimpleDateFormat("MM月dd日"); + return format.format(date); + } + + private void formatTime(TextView tv_time, String time) { + if (TextUtils.isEmpty(time)) return; + SimpleDateFormat timeFormat = new SimpleDateFormat("hh:mm"); + Date date = StringUtils.toDate(time); + tv_time.setText(formatWeek(date) + ", " + formatDate(date) + ", " + timeFormat.format(date)); + } + + /** + * 倒序 + * + * @param items items + */ + @Override + public void addAll(List items) { + if (items != null) { + mItems.addAll(0, items); + notifyDataSetChanged(); + } + + } + + private static class SenderViewHolder extends RecyclerView.ViewHolder { + TweetTextView tv_sender; + TextView tv_send_time; + + public SenderViewHolder(View itemView) { + super(itemView); + tv_sender = (TweetTextView) itemView.findViewById(R.id.tv_sender); + tv_send_time = (TextView) itemView.findViewById(R.id.tv_send_time); + } + } + + private static class SenderPictureViewHolder extends RecyclerView.ViewHolder { + ImageView iv_sender_picture, iv_resend; + TextView tv_send_time; + Loading loading; + + public SenderPictureViewHolder(View itemView) { + super(itemView); + iv_sender_picture = (ImageView) itemView.findViewById(R.id.iv_sender_picture); + iv_resend = (ImageView) itemView.findViewById(R.id.iv_resend); + tv_send_time = (TextView) itemView.findViewById(R.id.tv_send_time); + loading = (Loading) itemView.findViewById(R.id.loading); + } + } + + private static class ReceiverViewHolder extends RecyclerView.ViewHolder { + TweetTextView tv_receiver; + TextView tv_send_time; + + public ReceiverViewHolder(View itemView) { + super(itemView); + tv_receiver = (TweetTextView) itemView.findViewById(R.id.tv_receiver); + tv_send_time = (TextView) itemView.findViewById(R.id.tv_send_time); + + } + } + + private static class ReceiverPictureViewHolder extends RecyclerView.ViewHolder { + ImageView iv_receiver_picture; + TextView tv_send_time; + Loading loading; + + public ReceiverPictureViewHolder(View itemView) { + super(itemView); + iv_receiver_picture = (ImageView) itemView.findViewById(R.id.iv_receiver_picture); + tv_send_time = (TextView) itemView.findViewById(R.id.tv_send_time); + loading = (Loading) itemView.findViewById(R.id.loading); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/user/adapter/UserTweetAdapter.java b/app/src/main/java/net/oschina/app/improve/user/adapter/UserTweetAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..39d0bdf4830ed45f089b00d51ab09f92ffc1e1f8 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/adapter/UserTweetAdapter.java @@ -0,0 +1,294 @@ +package net.oschina.app.improve.user.adapter; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.support.v7.widget.RecyclerView; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.TextUtils; +import android.text.method.LinkMovementMethod; +import android.text.style.ForegroundColorSpan; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.base.adapter.BaseGeneralRecyclerAdapter; +import net.oschina.app.improve.bean.Tweet; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.bean.simple.About; +import net.oschina.app.improve.bean.simple.TweetLikeReverse; +import net.oschina.app.improve.user.activities.OtherUserHomeActivity; +import net.oschina.app.improve.utils.AssimilateUtils; +import net.oschina.app.improve.widget.SimplexToast; +import net.oschina.app.improve.widget.TweetPicturesLayout; +import net.oschina.app.util.ImageUtils; +import net.oschina.app.util.PlatfromUtil; +import net.oschina.app.util.StringUtils; +import net.oschina.app.util.UIHelper; +import net.oschina.app.widget.TweetTextView; + +import org.kymjs.kjframe.utils.DensityUtils; + +import java.lang.reflect.Type; + +import butterknife.Bind; +import butterknife.ButterKnife; +import cz.msebera.android.httpclient.Header; +import de.hdodenhof.circleimageview.CircleImageView; + +/** + * Created by + * thanatos on 16/8/17. + *

    + * 突然间变成各个地方都在用的Adapter了... + */ +public class UserTweetAdapter extends BaseGeneralRecyclerAdapter implements View.OnClickListener { + private Bitmap mRecordBitmap; + private View.OnClickListener mOnLikeClickListener; + + public UserTweetAdapter(Callback callback, int mode) { + super(callback, mode); + initListener(); + } + + private void initListener() { + mOnLikeClickListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + if (!AccountHelper.isLogin()) { + UIHelper.showLoginActivity(mContext); + return; + } + final int position = Integer.valueOf(v.getTag().toString()); + Tweet tweet = getItem(position); + if (tweet == null) return; + OSChinaApi.reverseTweetLike(tweet.getId(), new TweetLikedHandler(position)); + } + }; + } + + private void initRecordImg(Context cxt) { + mRecordBitmap = BitmapFactory.decodeResource(cxt.getResources(), R.mipmap.audio3); + mRecordBitmap = ImageUtils.zoomBitmap(mRecordBitmap, + DensityUtils.dip2px(cxt, 20f), DensityUtils.dip2px(cxt, 20f)); + } + + @Override + protected RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type) { + return new ViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item_list_tweet_improve, parent, false)); + } + + @Override + protected void onBindDefaultViewHolder(RecyclerView.ViewHolder h, final Tweet item, int position) { + ViewHolder holder = (ViewHolder) h; + mCallBack.getImgLoader() + .load(item.getAuthor().getPortrait()) + .asBitmap() + .placeholder(R.mipmap.widget_dface) + .error(R.mipmap.widget_dface) + .into(holder.mViewPortrait); + holder.mViewPortrait.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + OtherUserHomeActivity.show(mContext, item.getAuthor()); + } + }); + + holder.mViewName.setText(item.getAuthor().getName()); + holder.mViewTime.setText(StringUtils.formatSomeAgo(item.getPubDate())); + PlatfromUtil.setPlatFromString(holder.mViewPlatform, item.getAppClient()); + + if (!TextUtils.isEmpty(item.getContent())) { + String content = item.getContent().replaceAll("[\n\\s]+", " "); + holder.mViewContent.setText(AssimilateUtils.assimilate(mContext, content)); + holder.mViewContent.setMovementMethod(LinkMovementMethod.getInstance()); + holder.mViewContent.setFocusable(false); + holder.mViewContent.setDispatchToParent(true); + holder.mViewContent.setLongClickable(false); + } + + /* - @hide - */ + /*if (item.getAudio() != null) { + if (mRecordBitmap == null) { + initRecordImg(mContext); + } + ImageSpan recordImg = new ImageSpan(mContext, mRecordBitmap); + SpannableString str = new SpannableString("c"); + str.setSpan(recordImg, 0, 1, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); + holder.mViewContent.setText(str); + holder.mViewContent.append(spannable); + } else { + holder.mViewContent.setText(spannable); + }*/ + + holder.mViewLikeState.setImageResource( + item.isLiked() + ? R.mipmap.ic_thumbup_actived + : R.mipmap.ic_thumb_normal); + holder.mViewLikeState.setTag(position); + holder.mViewLikeState.setOnClickListener(mOnLikeClickListener); + + Tweet.Image[] images = item.getImages(); + holder.mLayoutFlow.setImage(images); + + /* - statistics - */ + if (item.getStatistics() != null) { + holder.mViewLikeCount.setText(String.valueOf(item.getStatistics().getLike())); + holder.mViewCmmCount.setText(String.valueOf(item.getStatistics().getComment())); + int mDispatchCount = item.getStatistics().getTransmit(); + if (mDispatchCount <= 0) { + holder.mViewDispatchCount.setVisibility(View.GONE); + } else { + holder.mViewDispatchCount.setVisibility(View.VISIBLE); + holder.mViewDispatchCount.setText(String.valueOf(item.getStatistics().getTransmit())); + } + } else { + holder.mViewLikeCount.setText(String.valueOf(item.getLikeCount())); + holder.mViewCmmCount.setText(String.valueOf(item.getCommentCount())); + holder.mViewDispatchCount.setVisibility(View.GONE); + } + + if (item.getAbout() != null) { + holder.mLayoutRef.setVisibility(View.VISIBLE); + holder.mLayoutRef.setTag(position); + holder.mLayoutRef.setOnClickListener(this); + + About about = item.getAbout(); + holder.mLayoutRefImages.setImage(about.getImages()); + + if (!About.check(about)) { + holder.mViewRefTitle.setVisibility(View.VISIBLE); + holder.mViewRefTitle.setText("不存在或已删除的内容"); + holder.mViewRefContent.setText("抱歉,该内容不存在或已被删除"); + } else { + if (about.getType() == OSChinaApi.COMMENT_TWEET) { + holder.mViewRefTitle.setVisibility(View.GONE); + String aname = "@" + about.getTitle(); + String cnt = about.getContent(); + Spannable spannable = AssimilateUtils.assimilate(mContext, cnt); + SpannableStringBuilder builder = new SpannableStringBuilder(); + builder.append(aname + ": "); + builder.append(spannable); + ForegroundColorSpan span = new ForegroundColorSpan( + mContext.getResources().getColor(R.color.day_colorPrimary)); + builder.setSpan(span, 0, aname.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); + holder.mViewRefContent.setMaxLines(Integer.MAX_VALUE); + holder.mViewRefContent.setText(builder); + } else { + holder.mViewRefTitle.setVisibility(View.VISIBLE); + holder.mViewRefTitle.setText(about.getTitle()); + holder.mViewRefContent.setMaxLines(3); + holder.mViewRefContent.setEllipsize(TextUtils.TruncateAt.END); + holder.mViewRefContent.setText(about.getContent()); + } + } + } else { + holder.mLayoutRef.setVisibility(View.GONE); + } + } + + /** + * 点击引用时触发 + * + * @param v Ref View + */ + @Override + public void onClick(View v) { + int position = Integer.valueOf(v.getTag().toString()); + Tweet tweet = getItem(position); + if (tweet == null) return; + About about = tweet.getAbout(); + if (about == null) return; + UIHelper.showDetail(mContext, about.getType(), about.getId(), about.getHref()); + } + + /** + * Tweet Item View Holder + */ + public static class ViewHolder extends RecyclerView.ViewHolder { + @Bind(R.id.iv_tweet_face) + CircleImageView mViewPortrait; + @Bind(R.id.tv_tweet_name) + TextView mViewName; + @Bind(R.id.tv_tweet_time) + TextView mViewTime; + @Bind(R.id.tv_tweet_platform) + TextView mViewPlatform; + @Bind(R.id.tv_tweet_like_count) + TextView mViewLikeCount; + @Bind(R.id.tv_tweet_comment_count) + TextView mViewCmmCount; + @Bind(R.id.tweet_item) + TweetTextView mViewContent; + @Bind(R.id.iv_like_state) + ImageView mViewLikeState; + @Bind(R.id.fl_image) + TweetPicturesLayout mLayoutFlow; + @Bind(R.id.tv_ref_title) + TextView mViewRefTitle; + @Bind(R.id.tv_ref_content) + TextView mViewRefContent; + @Bind(R.id.layout_ref_images) + TweetPicturesLayout mLayoutRefImages; + @Bind(R.id.iv_dispatch) + ImageView mViewDispatch; + @Bind(R.id.tv_dispatch_count) + TextView mViewDispatchCount; + @Bind(R.id.layout_ref) + LinearLayout mLayoutRef; + + + public ViewHolder(View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + } + + /** + * 点赞请求的回调 + */ + private class TweetLikedHandler extends TextHttpResponseHandler { + private int position; + + TweetLikedHandler(int position) { + this.position = position; + } + + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + SimplexToast.show(mContext, "点赞操作失败"); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + Type type = new TypeToken>() { + }.getType(); + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, type); + Tweet tweet = getItem(position); + if (tweet == null) return; + tweet.setLiked(resultBean.getResult().isLiked()); + tweet.setLikeCount(resultBean.getResult().getLikeCount()); + if (tweet.getStatistics() != null) { + tweet.getStatistics().setLike(resultBean.getResult().getLikeCount()); + } + updateItem(position); + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/user/bean/UserFansOrFollows.java b/app/src/main/java/net/oschina/app/improve/user/bean/UserFansOrFollows.java new file mode 100644 index 0000000000000000000000000000000000000000..9fcb8732acacac2650e4facc4a1f357988db48fd --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/bean/UserFansOrFollows.java @@ -0,0 +1,136 @@ +package net.oschina.app.improve.user.bean; + +import java.io.Serializable; + +/** + * Created by fei on 2016/8/24. + * desc: + */ + +public class UserFansOrFollows implements Serializable { + private long id; + private String name; + private String portrait;//0 未知 1 男 2 女 + private int gender; + private String desc; + private int relation; + private More more; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPortrait() { + return portrait; + } + + public void setPortrait(String portrait) { + this.portrait = portrait; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + + public int getGender() { + return gender; + } + + public void setGender(int gender) { + this.gender = gender; + } + + public int getRelation() { + return relation; + } + + public void setRelation(int relation) { + this.relation = relation; + } + + public More getMore() { + return more; + } + + public void setMore(More more) { + this.more = more; + } + + public static class More implements Serializable { + private String joinDate; + private String city; + private String expertise; + private String platform; + + public String getJoinDate() { + return joinDate; + } + + public void setJoinDate(String joinDate) { + this.joinDate = joinDate; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getExpertise() { + return expertise; + } + + public void setExpertise(String expertise) { + this.expertise = expertise; + } + + public String getPlatform() { + return platform; + } + + public void setPlatform(String platform) { + this.platform = platform; + } + + @Override + public String toString() { + return "More{" + + "joinDate='" + joinDate + '\'' + + ", city='" + city + '\'' + + ", expertise='" + expertise + '\'' + + ", platform='" + platform + '\'' + + '}'; + } + } + + @Override + public String toString() { + return "UserFansOrFollows{" + + "id=" + id + + ", name='" + name + '\'' + + ", portrait='" + portrait + '\'' + + ", gender=" + gender + + ", desc='" + desc + '\'' + + ", relation=" + relation + + ", more=" + more + + '}'; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/user/bean/UserFavorites.java b/app/src/main/java/net/oschina/app/improve/user/bean/UserFavorites.java new file mode 100644 index 0000000000000000000000000000000000000000..d75bf765fa6d897fa8e7f50371d5d16eb62fedec --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/bean/UserFavorites.java @@ -0,0 +1,58 @@ +package net.oschina.app.improve.user.bean; + +import java.io.Serializable; + +/** + * Created by fei on 2016/8/30. + * desc: + */ + +public class UserFavorites implements Serializable { + + private long id; + private int type; + private String title; + private String href; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getHref() { + return href; + } + + public void setHref(String href) { + this.href = href; + } + + @Override + public String toString() { + return "UserFavorites{" + + "id=" + id + + ", type=" + type + + ", title='" + title + '\'' + + ", href='" + href + '\'' + + '}'; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/user/bean/UserInfo.java b/app/src/main/java/net/oschina/app/improve/user/bean/UserInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..392bb7a058462604582dc2bf8f13a735c421bbc2 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/bean/UserInfo.java @@ -0,0 +1,118 @@ +package net.oschina.app.improve.user.bean; + +import java.io.Serializable; + +/** + * Created by fei on 2016/8/19. + * desc: user info module + */ + +public class UserInfo implements Serializable { + + private long id; + private String name; + private String portrait; + private int gender; + private String desc; + private int score; + private int tweetCount; + private int collectCount; + private int fansCount; + private int followCount; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPortrait() { + return portrait; + } + + public void setPortrait(String portrait) { + this.portrait = portrait; + } + + public int getGender() { + return gender; + } + + public void setGender(int gender) { + this.gender = gender; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + + public int getScore() { + return score; + } + + public void setScore(int score) { + this.score = score; + } + + public int getTweetCount() { + return tweetCount; + } + + public void setTweetCount(int tweetCount) { + this.tweetCount = tweetCount; + } + + public int getFansCount() { + return fansCount; + } + + public void setFansCount(int fansCount) { + this.fansCount = fansCount; + } + + public int getFollowCount() { + return followCount; + } + + public void setFollowCount(int followCount) { + this.followCount = followCount; + } + + public int getCollectCount() { + return collectCount; + } + + public void setCollectCount(int collectCount) { + this.collectCount = collectCount; + } + + @Override + public String toString() { + return "UserInfo{" + + "id=" + id + + ", name='" + name + '\'' + + ", portrait='" + portrait + '\'' + + ", gender=" + gender + + ", desc='" + desc + '\'' + + ", score=" + score + + ", tweetCount=" + tweetCount + + ", collectCount=" + collectCount + + ", fansCount=" + fansCount + + ", followCount=" + followCount + + '}'; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/user/fragments/UserActiveFragment.java b/app/src/main/java/net/oschina/app/improve/user/fragments/UserActiveFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..30e046ae2d3da70fadfd2176dea68bfb9dbc839a --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/fragments/UserActiveFragment.java @@ -0,0 +1,113 @@ +package net.oschina.app.improve.user.fragments; + +import android.os.Bundle; +import android.support.v4.app.Fragment; + +import com.bumptech.glide.Glide; +import com.google.gson.reflect.TypeToken; + +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.base.fragments.BaseRecyclerViewFragment; +import net.oschina.app.improve.bean.Active; +import net.oschina.app.improve.bean.base.PageBean; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.bean.simple.Origin; +import net.oschina.app.improve.detail.activities.BlogDetailActivity; +import net.oschina.app.improve.detail.activities.EventDetailActivity; +import net.oschina.app.improve.detail.activities.NewsDetailActivity; +import net.oschina.app.improve.detail.activities.QuestionDetailActivity; +import net.oschina.app.improve.detail.activities.SoftwareDetailActivity; +import net.oschina.app.improve.tweet.activities.TweetDetailActivity; +import net.oschina.app.improve.user.adapter.UserActiveAdapter; +import net.oschina.app.util.UIHelper; + +import java.lang.reflect.Type; + + +/** + * 某用户的动态(讨论)列表 + * Created by thanatos on 16/8/16. + */ +public class UserActiveFragment extends BaseRecyclerViewFragment { + + public static final String BUNDLE_KEY_USER_ID = "BUNDLE_KEY_USER_ID"; + + private long uid; + + public static Fragment instantiate(Long uid) { + Bundle bundle = new Bundle(); + bundle.putLong(BUNDLE_KEY_USER_ID, uid); + Fragment fragment = new UserActiveFragment(); + fragment.setArguments(bundle); + return fragment; + } + + @Override + protected void initBundle(Bundle bundle) { + super.initBundle(bundle); + uid = bundle.getLong(BUNDLE_KEY_USER_ID); + } + + @Override + protected BaseRecyclerAdapter getRecyclerAdapter() { + return new UserActiveAdapter(getContext(), Glide.with(this)); + } + + @Override + protected Type getType() { + return new TypeToken>>() { + }.getType(); + } + + @Override + protected void requestData() { + String token = isRefreshing ? null : mBean.getNextPageToken(); + OSChinaApi.getUserActives(uid, token, mHandler); + } + + @Override + public void onItemClick(int position, long itemId) { + Origin origin = mAdapter.getItem(position).getOrigin(); + if (origin == null) + return; + switch (origin.getType()) { + case Origin.ORIGIN_TYPE_LINK: + UIHelper.showUrlRedirect(getContext(), origin.getHref()); + break; + case Origin.ORIGIN_TYPE_SOFTWARE: + SoftwareDetailActivity.show(getContext(), origin.getId()); + break; + case Origin.ORIGIN_TYPE_DISCUSS: + QuestionDetailActivity.show(getContext(), origin.getId()); + break; + case Origin.ORIGIN_TYPE_BLOG: + BlogDetailActivity.show(getContext(), origin.getId()); + break; + case Origin.ORIGIN_TYPE_TRANSLATION: + NewsDetailActivity.show(getContext(), origin.getId()); + break; + case Origin.ORIGIN_TYPE_ACTIVE: + EventDetailActivity.show(getContext(), origin.getId()); + break; + case Origin.ORIGIN_TYPE_NEWS: + NewsDetailActivity.show(getContext(), origin.getId()); + break; + case Origin.ORIGIN_TYPE_TWEETS: + TweetDetailActivity.show(getContext(), origin.getId()); + break; + default: + // pass + } + } + + @Override + protected boolean isNeedCache() { + return false; + } + + @Override + protected boolean isNeedEmptyView() { + return false; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/user/fragments/UserBlogFragment.java b/app/src/main/java/net/oschina/app/improve/user/fragments/UserBlogFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..c995c1597238c77a6e0bb60aefab65ea1c8f170a --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/fragments/UserBlogFragment.java @@ -0,0 +1,77 @@ +package net.oschina.app.improve.user.fragments; + + +import android.os.Bundle; +import android.support.v4.app.Fragment; + +import com.google.gson.reflect.TypeToken; + +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.base.fragments.BaseRecyclerViewFragment; +import net.oschina.app.improve.bean.SubBean; +import net.oschina.app.improve.bean.base.PageBean; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.detail.activities.BlogDetailActivity; +import net.oschina.app.improve.main.subscription.BlogSubAdapter; + +import java.lang.reflect.Type; + +/** + * created by thanatosx on 2016/8/16. + */ +public class UserBlogFragment extends BaseRecyclerViewFragment { + + public static final String HISTORY_BLOG = "history_my_blog"; + public static final String BUNDLE_KEY_USER_ID = "BUNDLE_KEY_USER_ID"; + private long userId; + + public static Fragment instantiate(long uid) { + Bundle bundle = new Bundle(); + bundle.putLong(BUNDLE_KEY_USER_ID, uid); + Fragment fragment = new UserBlogFragment(); + fragment.setArguments(bundle); + return fragment; + } + + @Override + protected void initBundle(Bundle bundle) { + super.initBundle(bundle); + userId = bundle.getLong(BUNDLE_KEY_USER_ID); + } + + @Override + protected void requestData() { + super.requestData(); + String token = isRefreshing ? null : mBean.getNextPageToken(); + OSChinaApi.getSomeoneBlogs(token, userId, null, mHandler); + } + + @Override + protected BaseRecyclerAdapter getRecyclerAdapter() { + return new BlogSubAdapter(getContext(), BaseRecyclerAdapter.ONLY_FOOTER); + } + + @Override + protected Type getType() { + return new TypeToken>>() { + }.getType(); + } + + @Override + protected boolean isNeedCache() { + return false; + } + + @Override + protected boolean isNeedEmptyView() { + return false; + } + + @Override + public void onItemClick(int position, long itemId) { + SubBean blog = mAdapter.getItem(position); + if (blog == null) return; + BlogDetailActivity.show(getActivity(), blog.getId()); + } +} \ No newline at end of file diff --git a/app/src/main/java/net/oschina/app/improve/user/fragments/UserCommentFragment.java b/app/src/main/java/net/oschina/app/improve/user/fragments/UserCommentFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..8a0a44f06c51140872509205081a75f15c4e58dc --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/fragments/UserCommentFragment.java @@ -0,0 +1,102 @@ +package net.oschina.app.improve.user.fragments; + +import android.content.Context; + +import com.google.gson.reflect.TypeToken; + +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.base.fragments.BaseRecyclerViewFragment; +import net.oschina.app.improve.bean.Mention; +import net.oschina.app.improve.bean.base.PageBean; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.bean.simple.Origin; +import net.oschina.app.improve.detail.activities.BlogDetailActivity; +import net.oschina.app.improve.detail.activities.EventDetailActivity; +import net.oschina.app.improve.detail.activities.NewsDetailActivity; +import net.oschina.app.improve.detail.activities.QuestionDetailActivity; +import net.oschina.app.improve.detail.activities.SoftwareDetailActivity; +import net.oschina.app.improve.tweet.activities.TweetDetailActivity; +import net.oschina.app.improve.user.activities.UserMessageActivity; +import net.oschina.app.improve.user.adapter.UserMentionAdapter; +import net.oschina.app.util.UIHelper; + +import java.lang.reflect.Type; + +/** + * Created by huanghaibin_dev + * on 2016/8/16. + */ + +public class UserCommentFragment extends BaseRecyclerViewFragment { + + + private UserMessageActivity activity; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + if (context != null && context instanceof UserMessageActivity) { + activity = (UserMessageActivity) context; + } + } + + @Override + protected void onRequestSuccess(int code) { + super.onRequestSuccess(code); + if (activity != null) activity.onRequestSuccess(1); + } + + @Override + protected void requestData() { + super.requestData(); + OSChinaApi.getMsgCommentList(isRefreshing ? null : mBean.getNextPageToken(), mHandler); + } + + @Override + public void onItemClick(int position, long itemId) { + Mention mention = mAdapter.getItem(position); + if (mention == null) + return; + Origin origin = mention.getOrigin(); + switch (origin.getType()) { + case Origin.ORIGIN_TYPE_LINK: + UIHelper.showUrlRedirect(getContext(), origin.getHref()); + break; + case Origin.ORIGIN_TYPE_SOFTWARE: + SoftwareDetailActivity.show(getContext(), origin.getId()); + break; + case Origin.ORIGIN_TYPE_DISCUSS: + QuestionDetailActivity.show(getContext(), origin.getId()); + break; + case Origin.ORIGIN_TYPE_BLOG: + BlogDetailActivity.show(getContext(), origin.getId()); + break; + case Origin.ORIGIN_TYPE_TRANSLATION: + NewsDetailActivity.show(getContext(), origin.getId()); + break; + case Origin.ORIGIN_TYPE_ACTIVE: + EventDetailActivity.show(getContext(), origin.getId()); + break; + case Origin.ORIGIN_TYPE_NEWS: + NewsDetailActivity.show(getContext(), origin.getId()); + break; + case Origin.ORIGIN_TYPE_TWEETS: + TweetDetailActivity.show(getContext(), origin.getId()); + break; + default: + // pass + } + } + + @Override + protected BaseRecyclerAdapter getRecyclerAdapter() { + return new UserMentionAdapter(this); + } + + @Override + protected Type getType() { + return new TypeToken>>() { + }.getType(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/user/fragments/UserEventFragment.java b/app/src/main/java/net/oschina/app/improve/user/fragments/UserEventFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..3c868f1b8d6ad25665af600da62e8216c3168aeb --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/fragments/UserEventFragment.java @@ -0,0 +1,142 @@ +package net.oschina.app.improve.user.fragments; + +import com.google.gson.reflect.TypeToken; + +import net.oschina.app.AppConfig; +import net.oschina.app.OSCApplication; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.base.fragments.BaseGeneralRecyclerFragment; +import net.oschina.app.improve.bean.News; +import net.oschina.app.improve.bean.SubBean; +import net.oschina.app.improve.bean.User; +import net.oschina.app.improve.bean.base.PageBean; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.detail.activities.EventDetailActivity; +import net.oschina.app.improve.user.adapter.UserEventAdapter; +import net.oschina.app.util.UIHelper; + +import java.lang.reflect.Type; + + +/** + * Created by fei + * on 2016/12/2. + * desc: + */ +public class UserEventFragment extends BaseGeneralRecyclerFragment { + + private OSCApplication.ReadState mReadState; + + /** + * init fragment + * + * @return fragment + */ + public static UserEventFragment newInstance() { + return new UserEventFragment(); + //return (UserEventFragment) Fragment.instantiate(context, UserEventFragment.class.getClass().getName(), bundle); + } + + + @Override + public void initData() { + CACHE_NAME = UserEventFragment.class.getName(); + mReadState = OSCApplication.getReadState("sub_list"); + super.initData(); + mAdapter.setSystemTime(AppConfig.getAppConfig(getActivity()).get("system_time")); + } + + @Override + public void onItemClick(int position, long itemId) { + SubBean sub = mAdapter.getItem(position); + if (sub == null) + return; + switch (sub.getType()) { + case News.TYPE_EVENT: + EventDetailActivity.show(mContext, sub.getId()); + break; + default: + UIHelper.showUrlRedirect(mContext, sub.getHref()); + break; + } + mReadState.put(sub.getKey()); + mAdapter.updateItem(position); + } + + @Override + public void onRefreshing() { + super.onRefreshing(); + +// List subBeans = new ArrayList<>(30); +// for (int i = 0; i < 30; i++) { +// +// SubBean subBean = new SubBean(); +// subBean.setId(2193441); +// subBean.setTitle("这是我的活动" + i); +// subBean.setBody("这是body" + i); +// subBean.setPubDate("013-09-17 16:49:50.222"); +// subBean.setHref("http://www.oschina.net"); +// subBean.setType(5); +// Author author = new Author(); +// author.setId(AccountHelper.getUserId()); +// author.setName(AccountHelper.getUser().getName() + i); +// author.setPortrait(AccountHelper.getUser().getPortrait()); +// subBean.setAuthor(author); +// SubBean.Image image = new SubBean.Image(); +// image.setType(2); +// String[] href = new String[]{AccountHelper.getUser().getPortrait(), +// AccountHelper.getUser().getPortrait(), AccountHelper.getUser().getPortrait()}; +// image.setHref(href); +// subBean.setImage(image); +// String[] tags = new String[]{"recommend", "original", "ad", "stick"}; +// subBean.setTags(tags); +// SubBean.Statistics statistics = new SubBean.Statistics(); +// statistics.setView(300); +// statistics.setComment(500); +// subBean.setStatistics(statistics); +// +// subBeans.add(subBean); +// } +// +// mBean.setItems(subBeans); + + } + + @Override + protected void onRequestFinish() { + super.onRequestFinish(); + } + + @Override + protected void requestData() { + super.requestData(); + User user = AccountHelper.getUser(); + if (user != null) + OSChinaApi.getUserEvent(user.getId(), user.getName(), isRefreshing ? null : mBean.getNextPageToken(), mHandler); + } + + @Override + protected void setListData(ResultBean> resultBean) { + super.setListData(resultBean); + mAdapter.setSystemTime(resultBean.getTime()); + } + + @Override + protected BaseRecyclerAdapter getRecyclerAdapter() { + return new UserEventAdapter(this, BaseRecyclerAdapter.ONLY_FOOTER); + } + + @Override + protected Type getType() { + return new TypeToken>>() { + }.getType(); + } + + @Override + protected Class getCacheClass() { + return SubBean.class; + } + +} diff --git a/app/src/main/java/net/oschina/app/improve/user/fragments/UserFavoriteFragment.java b/app/src/main/java/net/oschina/app/improve/user/fragments/UserFavoriteFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..b3e10de246fc82259fa40f7a1afb6d15f808e9ef --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/fragments/UserFavoriteFragment.java @@ -0,0 +1,111 @@ +package net.oschina.app.improve.user.fragments; + +import android.os.Bundle; + +import com.google.gson.reflect.TypeToken; + +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.base.fragments.BaseRecyclerViewFragment; +import net.oschina.app.improve.bean.base.PageBean; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.detail.activities.BlogDetailActivity; +import net.oschina.app.improve.detail.activities.EventDetailActivity; +import net.oschina.app.improve.detail.activities.NewsDetailActivity; +import net.oschina.app.improve.detail.activities.QuestionDetailActivity; +import net.oschina.app.improve.detail.activities.SoftwareDetailActivity; +import net.oschina.app.improve.detail.activities.TranslateDetailActivity; +import net.oschina.app.improve.user.adapter.UserFavoritesAdapter; +import net.oschina.app.improve.user.bean.UserFavorites; + +import java.lang.reflect.Type; + +/** + * Created by fei on 2016/8/30. + * desc: + */ + +public class UserFavoriteFragment extends BaseRecyclerViewFragment { + + public static final String CATALOG_TYPE = "catalog_type"; + private int catalog; + + @Override + protected void initBundle(Bundle bundle) { + super.initBundle(bundle); + catalog = bundle.getInt(CATALOG_TYPE); + } + + @Override + protected void requestData() { + super.requestData(); + switch (catalog) { + case 0: + CACHE_NAME = "user_favorite_all"; + break; + case 1: + CACHE_NAME = "user_favorite_software"; + break; + case 2: + CACHE_NAME = "user_favorite_question"; + break; + case 3: + CACHE_NAME = "user_favorite_blog"; + break; + case 4: + CACHE_NAME = "user_favorite_traslation"; + break; + case 5: + CACHE_NAME = "user_favorite_event"; + break; + case 6: + CACHE_NAME = "user_favorite_news"; + break; + default: + break; + } + OSChinaApi.getUserFavorites(catalog, isRefreshing ? null : mBean.getNextPageToken(), mHandler); + } + + + @Override + protected BaseRecyclerAdapter getRecyclerAdapter() { + return new UserFavoritesAdapter(getActivity(), BaseRecyclerAdapter.ONLY_FOOTER); + } + + @Override + protected Type getType() { + return new TypeToken>>() { + }.getType(); + } + + @Override + public void onItemClick(int position, long itemId) { + UserFavorites item = mAdapter.getItem(position); + if (item == null) return; + int type = item.getType(); + switch (type) { + case 1: + SoftwareDetailActivity.show(getActivity(), item.getId()); + break; + case 2: + QuestionDetailActivity.show(getActivity(), item.getId()); + break; + case 3: + BlogDetailActivity.show(getActivity(), item.getId()); + break; + case 4: + TranslateDetailActivity.show(getActivity(), item.getId()); + break; + case 5: + EventDetailActivity.show(getActivity(), item.getId()); + break; + case 6: + NewsDetailActivity.show(getActivity(), item.getId()); + break; + default: + break; + } + + } +} diff --git a/app/src/main/java/net/oschina/app/improve/user/fragments/UserInfoFragment.java b/app/src/main/java/net/oschina/app/improve/user/fragments/UserInfoFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..cf8a9c19df4a1c02373d40fedd9c046af2f38d93 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/fragments/UserInfoFragment.java @@ -0,0 +1,608 @@ +package net.oschina.app.improve.user.fragments; + +import android.app.ProgressDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.provider.MediaStore; +import android.support.annotation.NonNull; +import android.text.TextUtils; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.AppContext; +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.bean.SimpleBackPage; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.account.activity.LoginActivity; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.base.fragments.BaseFragment; +import net.oschina.app.improve.bean.User; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.media.SelectImageActivity; +import net.oschina.app.improve.media.config.SelectOptions; +import net.oschina.app.improve.notice.NoticeBean; +import net.oschina.app.improve.notice.NoticeManager; +import net.oschina.app.improve.user.activities.UserCollectionActivity; +import net.oschina.app.improve.user.activities.UserFansActivity; +import net.oschina.app.improve.user.activities.UserFollowsActivity; +import net.oschina.app.improve.user.activities.UserMessageActivity; +import net.oschina.app.improve.user.activities.UserTweetActivity; +import net.oschina.app.improve.utils.DialogHelper; +import net.oschina.app.improve.widget.SolarSystemView; +import net.oschina.app.improve.widget.TitleBar; +import net.oschina.app.interf.OnTabReselectListener; +import net.oschina.app.ui.MyQRCodeDialog; +import net.oschina.app.ui.SimpleBackActivity; +import net.oschina.app.util.ImageUtils; +import net.oschina.app.util.TDevice; +import net.oschina.app.util.UIHelper; + +import java.io.File; +import java.lang.reflect.Type; +import java.util.List; +import java.util.Random; + +import butterknife.Bind; +import butterknife.OnClick; +import cz.msebera.android.httpclient.Header; +import de.hdodenhof.circleimageview.CircleImageView; +import pub.devrel.easypermissions.EasyPermissions; + +/** + * Created by fei on 2016/8/15. + *

    + * 用户个人界面 + */ + +public class UserInfoFragment extends BaseFragment implements View.OnClickListener, + EasyPermissions.PermissionCallbacks, NoticeManager.NoticeNotify, OnTabReselectListener { + + @Bind(R.id.iv_logo_setting) + ImageView mIvLogoSetting; + @Bind(R.id.iv_logo_zxing) + ImageView mIvLogoZxing; + @Bind(R.id.user_info_head_container) + FrameLayout mFlUserInfoHeadContainer; + + + @Bind(R.id.iv_portrait) + CircleImageView mCirclePortrait; + @Bind(R.id.iv_gender) + ImageView mIvGander; + @Bind(R.id.user_info_icon_container) + FrameLayout mFlUserInfoIconContainer; + + @Bind(R.id.tv_nick) + TextView mTvName; + @Bind(R.id.tv_score) + TextView mTvScore; + @Bind(R.id.user_view_solar_system) + SolarSystemView mSolarSystem; + @Bind(R.id.rl_show_my_info) + LinearLayout mRlShowInfo; + + + @Bind(R.id.about_line) + View mAboutLine; + + @Bind(R.id.lay_about_info) + LinearLayout mLayAboutCount; + @Bind(R.id.tv_tweet) + TextView mTvTweetCount; + @Bind(R.id.tv_favorite) + TextView mTvFavoriteCount; + @Bind(R.id.tv_following) + TextView mTvFollowCount; + @Bind(R.id.tv_follower) + TextView mTvFollowerCount; + + @Bind(R.id.user_info_notice_message) + TextView mMesView; + + @Bind(R.id.user_info_notice_fans) + TextView mFansView; + + private boolean mIsUploadIcon; + private ProgressDialog mDialog; + + private int mMaxRadius; + private int mR; + private float mPx; + private float mPy; + + private File mCacheFile; + + private User mUserInfo; + + private TextHttpResponseHandler requestUserInfoHandler = new TextHttpResponseHandler() { + + @Override + public void onStart() { + super.onStart(); + if (mSolarSystem != null) mSolarSystem.accelerate(); + if (mIsUploadIcon) { + showWaitDialog(R.string.title_updating_user_avatar); + } + } + + @Override + public void onFailure(int statusCode, Header[] headers, String responseString + , Throwable throwable) { + if (mIsUploadIcon) { + Toast.makeText(getActivity(), R.string.title_update_fail_status, Toast.LENGTH_SHORT).show(); + deleteCacheImage(); + } + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + Type type = new TypeToken>() { + }.getType(); + + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, type); + if (resultBean.isSuccess()) { + User userInfo = (User) resultBean.getResult(); + updateView(userInfo); + //缓存用户信息 + AccountHelper.updateUserCache(userInfo); + } + if (mIsUploadIcon) { + deleteCacheImage(); + } + } catch (Exception e) { + e.printStackTrace(); + onFailure(statusCode, headers, responseString, e); + } + } + + @Override + public void onFinish() { + super.onFinish(); + if (mSolarSystem != null) mSolarSystem.decelerate(); + if (mIsUploadIcon) mIsUploadIcon = false; + if (mDialog != null && mDialog.isShowing()) mDialog.dismiss(); + } + }; + + + /** + * delete the cache image file for upload action + */ + @SuppressWarnings("ResultOfMethodCallIgnored") + private void deleteCacheImage() { + File file = this.mCacheFile; + if (file != null && file.exists()) { + file.delete(); + } + } + + @Override + protected int getLayoutId() { + return R.layout.fragment_main_user_home; + } + + @Override + protected void initWidget(View root) { + super.initWidget(root); + measureTitleBarHeight(); + + if (mFansView != null) + mFansView.setVisibility(View.INVISIBLE); + + initSolar(); + + } + + @Override + protected void initData() { + super.initData(); + NoticeManager.bindNotify(this); + requestUserCache(); + } + + @Override + public void onResume() { + super.onResume(); + mIsUploadIcon = false; + if (AccountHelper.isLogin()) { + User user = AccountHelper.getUser(); + updateView(user); + } else { + hideView(); + } + } + + /** + * if user isLogin,request user cache, + * And then request user info and update user info + */ + private void requestUserCache() { + if (AccountHelper.isLogin()) { + User user = AccountHelper.getUser(); + updateView(user); + sendRequestData(); + } else { + hideView(); + } + } + + @Override + public void onPause() { + super.onPause(); + if (!AccountHelper.isLogin()) { + hideView(); + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + NoticeManager.unBindNotify(this); + } + + /** + * update the view + * + * @param userInfo userInfo + */ + private void updateView(User userInfo) { + + setImageFromNet(mCirclePortrait, userInfo.getPortrait(), R.mipmap.widget_dface); + mCirclePortrait.setVisibility(View.VISIBLE); + + mTvName.setText(userInfo.getName()); + mTvName.setVisibility(View.VISIBLE); + mTvName.setTextSize(20.0f); + + switch (userInfo.getGender()) { + case 0: + mIvGander.setVisibility(View.INVISIBLE); + break; + case 1: + mIvGander.setVisibility(View.VISIBLE); + mIvGander.setImageResource(R.mipmap.ic_male); + break; + case 2: + mIvGander.setVisibility(View.VISIBLE); + mIvGander.setImageResource(R.mipmap.ic_female); + break; + default: + break; + } + + mTvScore.setText(String.format( + "%s %s", + getString(R.string.user_score), + formatCount(userInfo.getStatistics().getScore())) + ); + mTvScore.setVisibility(View.VISIBLE); + mAboutLine.setVisibility(View.VISIBLE); + mLayAboutCount.setVisibility(View.VISIBLE); + mTvTweetCount.setText(formatCount(userInfo.getStatistics().getTweet())); + mTvFavoriteCount.setText(formatCount(userInfo.getStatistics().getCollect())); + mTvFollowCount.setText(formatCount(userInfo.getStatistics().getFollow())); + mTvFollowerCount.setText(formatCount(userInfo.getStatistics().getFans())); + + mUserInfo = userInfo; + } + + /** + * format count + * + * @param count count + * @return formatCount + */ + private String formatCount(long count) { + + if (count > 1000) { + int a = (int) (count / 100); + int b = a % 10; + int c = a / 10; + String str; + if (c <= 9 && b != 0) + str = c + "." + b; + else + str = String.valueOf(c); + + return str + "k"; + } else { + return String.valueOf(count); + } + + } + + /** + * requestData + */ + private void sendRequestData() { + if (TDevice.hasInternet() && AccountHelper.isLogin()) + OSChinaApi.getUserInfo(requestUserInfoHandler); + } + + /** + * init solar view + */ + private void initSolar() { + View root = this.mRoot; + if (root != null) { + root.post(new Runnable() { + @Override + public void run() { + + if (mRlShowInfo == null) return; + int width = mRlShowInfo.getWidth(); + float rlShowInfoX = mRlShowInfo.getX(); + + int height = mFlUserInfoIconContainer.getHeight(); + float y1 = mFlUserInfoIconContainer.getY(); + + float x = mCirclePortrait.getX(); + float y = mCirclePortrait.getY(); + int portraitWidth = mCirclePortrait.getWidth(); + + mPx = x + +rlShowInfoX + (width >> 1); + mPy = y1 + y + (height - y) / 2; + mMaxRadius = (int) (mSolarSystem.getHeight() - mPy + 250); + mR = (portraitWidth >> 1); + + updateSolar(mPx, mPy); + + } + }); + } + } + + /** + * update solar + * + * @param px float + * @param py float + */ + private void updateSolar(float px, float py) { + + SolarSystemView solarSystemView = mSolarSystem; + Random random = new Random(System.currentTimeMillis()); + int maxRadius = mMaxRadius; + int r = mR; + solarSystemView.clear(); + for (int i = 40, radius = r + i; radius <= maxRadius; i = (int) (i * 1.4), radius += i) { + SolarSystemView.Planet planet = new SolarSystemView.Planet(); + planet.setClockwise(random.nextInt(10) % 2 == 0); + planet.setAngleRate((random.nextInt(35) + 1) / 1000.f); + planet.setRadius(radius); + solarSystemView.addPlanets(planet); + + } + solarSystemView.setPivotPoint(px, py); + } + + /** + * + */ + private void hideView() { + mCirclePortrait.setImageResource(R.mipmap.widget_dface); + mTvName.setText(R.string.user_hint_login); + mTvName.setTextSize(16.0f); + mIvGander.setVisibility(View.INVISIBLE); + mTvScore.setVisibility(View.INVISIBLE); + mLayAboutCount.setVisibility(View.GONE); + mAboutLine.setVisibility(View.GONE); + } + + /** + * measureTitleBarHeight + */ + private void measureTitleBarHeight() { + if (mRlShowInfo != null) { + mRlShowInfo.setPadding(mRlShowInfo.getLeft(), + TitleBar.getExtPaddingTop(getResources()), + mRlShowInfo.getRight(), mRlShowInfo.getBottom()); + } + } + + @SuppressWarnings("deprecation") + @OnClick({ + R.id.iv_logo_setting, R.id.iv_logo_zxing, R.id.iv_portrait, + R.id.user_view_solar_system, R.id.ly_tweet, R.id.ly_favorite, + R.id.ly_following, R.id.ly_follower, R.id.rl_message, R.id.rl_blog, + R.id.rl_info_question, R.id.rl_info_activities, R.id.rl_team + }) + @Override + public void onClick(View v) { + + int id = v.getId(); + + if (id == R.id.iv_logo_setting) { + UIHelper.showSetting(getActivity()); + } else { + + if (!AccountHelper.isLogin()) { + LoginActivity.show(getActivity()); + return; + } + + switch (id) { + case R.id.iv_logo_zxing: + MyQRCodeDialog dialog = new MyQRCodeDialog(getActivity()); + dialog.show(); + break; + case R.id.iv_portrait: + //查看头像 or 更换头像 + showAvatarOperation(); + break; + case R.id.user_view_solar_system: + //显示我的资料 + if (mUserInfo != null) { + Bundle userBundle = new Bundle(); + userBundle.putSerializable("user_info", mUserInfo); + UIHelper.showSimpleBack(getActivity(), + SimpleBackPage.MY_INFORMATION_DETAIL, userBundle); + } + break; + case R.id.ly_tweet: + UserTweetActivity.show(getActivity(), AccountHelper.getUserId()); + break; + case R.id.ly_favorite: + UserCollectionActivity.show(getActivity()); + break; + case R.id.ly_following: + UserFollowsActivity.show(getActivity(), AccountHelper.getUserId()); + break; + case R.id.ly_follower: + UserFansActivity.show(getActivity(), AccountHelper.getUserId()); + break; + case R.id.rl_message: + UserMessageActivity.show(getActivity()); + break; + case R.id.rl_blog: + UIHelper.showUserBlog(getActivity(), AccountHelper.getUserId()); + break; + case R.id.rl_info_question: + UIHelper.showUserQuestion(getActivity(), AccountHelper.getUserId()); + break; + case R.id.rl_info_activities: + + Bundle bundle = new Bundle(); + bundle.putInt(SimpleBackActivity.BUNDLE_KEY_ARGS, 1); + UIHelper.showSimpleBack(getActivity(), SimpleBackPage.MY_EVENT, bundle); + + //UserEventActivity.show(getActivity()); + + break; + case R.id.rl_team: + UIHelper.showTeamMainActivity(getActivity()); + break; + default: + break; + } + } + } + + /** + * 更换头像 or 查看头像 + */ + private void showAvatarOperation() { + if (!AccountHelper.isLogin()) { + LoginActivity.show(getActivity()); + } else { + DialogHelper.getSelectDialog(getActivity(), + getString(R.string.action_select), + getResources().getStringArray(R.array.avatar_option), "取消", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + switch (i) { + case 0: + SelectImageActivity.show(getContext(), new SelectOptions.Builder() + .setSelectCount(1) + .setHasCam(true) + .setCrop(700, 700) + .setCallback(new SelectOptions.Callback() { + @Override + public void doSelected(String[] images) { + String path = images[0]; + uploadNewPhoto(new File(path)); + } + }).build()); + break; + + case 1: + if (mUserInfo == null + || TextUtils.isEmpty(mUserInfo.getPortrait())) return; + UIHelper.showUserAvatar(getActivity(), mUserInfo.getPortrait()); + break; + } + } + }).show(); + } + } + + /** + * take photo + */ + private void startTakePhoto() { + Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + startActivityForResult(intent, + ImageUtils.REQUEST_CODE_GETIMAGE_BYCAMERA); + } + + public ProgressDialog showWaitDialog(int messageId) { + String message = getResources().getString(messageId); + if (mDialog == null) { + mDialog = DialogHelper.getProgressDialog(getActivity(), message); + } + + mDialog.setMessage(message); + mDialog.show(); + + return mDialog; + } + + /** + * update the new picture + */ + private void uploadNewPhoto(File file) { + // 获取头像缩略图 + if (file == null || !file.exists() || file.length() == 0) { + AppContext.showToast(getString(R.string.title_icon_null)); + } else { + mIsUploadIcon = true; + this.mCacheFile = file; + OSChinaApi.updateUserIcon(file, requestUserInfoHandler); + } + + } + + @Override + public void onPermissionsGranted(int requestCode, List perms) { + try { + startTakePhoto(); + } catch (Exception e) { + Toast.makeText(this.getContext(), R.string.permissions_camera_error, Toast.LENGTH_LONG).show(); + } + } + + @Override + public void onPermissionsDenied(int requestCode, List perms) { + Toast.makeText(this.getContext(), R.string.permissions_camera_error, Toast.LENGTH_LONG).show(); + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions + , @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + + EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); + } + + @Override + public void onNoticeArrived(NoticeBean bean) { + if (mMesView != null) { + int allCount = bean.getReview() + bean.getLetter() + bean.getMention(); + mMesView.setVisibility(allCount > 0 ? View.VISIBLE : View.GONE); + mMesView.setText(String.valueOf(allCount)); + } + if (mFansView != null) { + int fans = bean.getFans(); + mFansView.setVisibility(fans > 0 ? View.VISIBLE : View.GONE); + mFansView.setText(String.valueOf(fans)); + } + } + + + @Override + public void onTabReselect() { + sendRequestData(); + } + +} diff --git a/app/src/main/java/net/oschina/app/improve/user/fragments/UserMentionFragment.java b/app/src/main/java/net/oschina/app/improve/user/fragments/UserMentionFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..ef2015d044d306be082d32eb0afb1e20b20b4ed9 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/fragments/UserMentionFragment.java @@ -0,0 +1,99 @@ +package net.oschina.app.improve.user.fragments; + +import android.content.Context; + +import com.google.gson.reflect.TypeToken; + +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.base.fragments.BaseRecyclerViewFragment; +import net.oschina.app.improve.bean.Mention; +import net.oschina.app.improve.bean.base.PageBean; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.bean.simple.Origin; +import net.oschina.app.improve.detail.activities.BlogDetailActivity; +import net.oschina.app.improve.detail.activities.EventDetailActivity; +import net.oschina.app.improve.detail.activities.NewsDetailActivity; +import net.oschina.app.improve.detail.activities.QuestionDetailActivity; +import net.oschina.app.improve.detail.activities.SoftwareDetailActivity; +import net.oschina.app.improve.tweet.activities.TweetDetailActivity; +import net.oschina.app.improve.user.activities.UserMessageActivity; +import net.oschina.app.improve.user.adapter.UserMentionAdapter; +import net.oschina.app.util.UIHelper; + +import java.lang.reflect.Type; + +/** + * Created by huanghaibin_dev + * on 2016/8/16. + */ + +public class UserMentionFragment extends BaseRecyclerViewFragment { + + private UserMessageActivity activity; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + if (context != null && context instanceof UserMessageActivity) { + activity = (UserMessageActivity) context; + } + } + + @Override + protected void onRequestSuccess(int code) { + super.onRequestSuccess(code); + if (activity != null) activity.onRequestSuccess(0); + } + + @Override + protected void requestData() { + super.requestData(); + OSChinaApi.getMsgMentionList(isRefreshing ? null : mBean.getNextPageToken(), mHandler); + } + + @Override + public void onItemClick(int position, long itemId) { + Mention mention = mAdapter.getItem(position); + Origin origin = mention.getOrigin(); + switch (origin.getType()) { + case Origin.ORIGIN_TYPE_LINK: + UIHelper.showUrlRedirect(getContext(), origin.getHref()); + break; + case Origin.ORIGIN_TYPE_SOFTWARE: + SoftwareDetailActivity.show(getContext(), origin.getId()); + break; + case Origin.ORIGIN_TYPE_DISCUSS: + QuestionDetailActivity.show(getContext(), origin.getId()); + break; + case Origin.ORIGIN_TYPE_BLOG: + BlogDetailActivity.show(getContext(), origin.getId()); + break; + case Origin.ORIGIN_TYPE_TRANSLATION: + NewsDetailActivity.show(getContext(), origin.getId()); + break; + case Origin.ORIGIN_TYPE_ACTIVE: + EventDetailActivity.show(getContext(), origin.getId()); + break; + case Origin.ORIGIN_TYPE_NEWS: + NewsDetailActivity.show(getContext(), origin.getId()); + break; + case Origin.ORIGIN_TYPE_TWEETS: + TweetDetailActivity.show(getContext(), origin.getId()); + break; + default: + // pass + } + } + + @Override + protected BaseRecyclerAdapter getRecyclerAdapter() { + return new UserMentionAdapter(this); + } + + @Override + protected Type getType() { + return new TypeToken>>() { + }.getType(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/user/fragments/UserMessageFragment.java b/app/src/main/java/net/oschina/app/improve/user/fragments/UserMessageFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..2f06acbfa69ea06cc69e641dacaf863be8dce4e0 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/fragments/UserMessageFragment.java @@ -0,0 +1,88 @@ +package net.oschina.app.improve.user.fragments; + +import android.content.Context; + +import com.google.gson.reflect.TypeToken; + +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.base.fragments.BaseRecyclerViewFragment; +import net.oschina.app.improve.bean.Message; +import net.oschina.app.improve.bean.User; +import net.oschina.app.improve.bean.base.PageBean; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.user.activities.UserMessageActivity; +import net.oschina.app.improve.user.activities.UserSendMessageActivity; +import net.oschina.app.improve.user.adapter.UserMessageAdapter; + +import java.lang.reflect.Type; + +/** + * Created by huanghaibin_dev + * on 2016/8/16. + */ + +public class UserMessageFragment extends BaseRecyclerViewFragment { + + public long authorId; + + private UserMessageActivity activity; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + if (context != null && context instanceof UserMessageActivity) { + activity = (UserMessageActivity) context; + } + } + + @Override + protected void onRequestSuccess(int code) { + super.onRequestSuccess(code); + if (activity != null) activity.onRequestSuccess(2); + } + + @Override + public void initData() { + super.initData(); + authorId = AccountHelper.getUserId(); + } + + @Override + protected void requestData() { + super.requestData(); + OSChinaApi.getUserMessageList(isRefreshing ? null : mBean.getNextPageToken(), mHandler); + } + + @Override + public void onItemClick(int position, long itemId) { + Message message = mAdapter.getItem(position); + if (message == null) + return; + User sender = message.getSender(); + if (sender != null) + UserSendMessageActivity.show(getContext(), message.getSender()); + } + + @Override + protected BaseRecyclerAdapter getRecyclerAdapter() { + return new UserMessageAdapter(this); + } + + @Override + protected Type getType() { + return new TypeToken>>() { + }.getType(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/user/fragments/UserQuestionFragment.java b/app/src/main/java/net/oschina/app/improve/user/fragments/UserQuestionFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..d034b141a30066a41d97c360e81eab79e20ae67e --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/user/fragments/UserQuestionFragment.java @@ -0,0 +1,77 @@ +package net.oschina.app.improve.user.fragments; + + +import android.os.Bundle; +import android.support.v4.app.Fragment; + +import com.google.gson.reflect.TypeToken; + +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.improve.base.adapter.BaseRecyclerAdapter; +import net.oschina.app.improve.base.fragments.BaseRecyclerViewFragment; +import net.oschina.app.improve.bean.Question; +import net.oschina.app.improve.bean.base.PageBean; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.detail.activities.QuestionDetailActivity; +import net.oschina.app.improve.user.adapter.UserQuestionAdapter; + +import java.lang.reflect.Type; + +/** + * @author thanatosx + */ +public class UserQuestionFragment extends BaseRecyclerViewFragment { + + public static final String HISTORY_MY_QUESTION = "history_my_question"; + public static final String BUNDLE_KEY_AUTHOR_ID = "author_id"; + private long userId; + + public static Fragment instantiate(int authorId) { + UserQuestionFragment fragment = new UserQuestionFragment(); + Bundle bundle = new Bundle(); + bundle.putLong(BUNDLE_KEY_AUTHOR_ID, authorId); + fragment.setArguments(bundle); + return fragment; + } + + @Override + protected void initBundle(Bundle bundle) { + super.initBundle(bundle); + userId = bundle.getLong(BUNDLE_KEY_AUTHOR_ID, 0); + } + + @Override + protected void requestData() { + String token = isRefreshing ? null : mBean.getNextPageToken(); + OSChinaApi.getUserQuestionList(token, userId, mHandler); + } + + @Override + protected BaseRecyclerAdapter getRecyclerAdapter() { + return new UserQuestionAdapter(getContext(), BaseRecyclerAdapter.ONLY_FOOTER); + } + + @Override + protected Type getType() { + return new TypeToken>>() { + }.getType(); + } + + @Override + protected boolean isNeedCache() { + return false; + } + + @Override + protected boolean isNeedEmptyView() { + return false; + } + + @Override + public void onItemClick(int position, long itemId) { + Question question = mAdapter.getItem(position); + if (question == null) + return; + QuestionDetailActivity.show(getActivity(), question.getId()); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/utils/AssimilateUtils.java b/app/src/main/java/net/oschina/app/improve/utils/AssimilateUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..d8ea715e1cd53acae46ca73770c5ac45cb45fcd3 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/utils/AssimilateUtils.java @@ -0,0 +1,403 @@ +package net.oschina.app.improve.utils; + +import android.content.Context; +import android.os.Bundle; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.TextPaint; +import android.text.TextUtils; +import android.text.style.ClickableSpan; +import android.text.style.ForegroundColorSpan; +import android.util.Pair; +import android.view.View; + +import net.oschina.app.bean.SimpleBackPage; +import net.oschina.app.emoji.InputHelper; +import net.oschina.app.improve.user.activities.OtherUserHomeActivity; +import net.oschina.app.util.HTMLUtil; +import net.oschina.app.util.UIHelper; + +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * 后台很多String数据需要做本地化处理 + *

    + * Created by thanatos on 16/7/27. + */ +public class AssimilateUtils { + + // @thanatosx + // http://my.oschina.net/u/user_id + // http://my.oschina.net/user_ident + public static final Pattern PatternAtUserWithHtml = Pattern.compile( + "]*>(@([^@<>\\s]+))" + ); + public static final Pattern PatternAtUser = Pattern.compile( + "@[^@\\s:]+" + ); + + // #Java# + public static final Pattern PatternSoftwareTagWithHtml = Pattern.compile( + "]*>(#[^#@<>\\s]+#)" + ); + public static final Pattern PatternSoftwareTag = Pattern.compile( + "#([^#@<>\\s]+)#" + ); + + // @user links + @Deprecated + public static final Pattern PatternAtUserAndLinks = Pattern.compile( + "]*>(@[^@<>\\s]+)" + + "|]*>([^<>]*)" + ); + + // links + public static final Pattern PatternLinks = Pattern.compile( + "]*>([^<>]*)" + ); + + // team task + public static final Pattern PatternTeamTask = Pattern.compile( + "]*>([^<>]*)" + ); + + // html task + public static final Pattern PatternHtml = Pattern.compile( + "<[^<>]+>([^<>]+)]+>" + ); + + private interface Action1 { + void call(String str); + } + + /** + * 通常使用的过滤逻辑 + * + * @param context {@link Context} + * @param content Content String + * @return String + */ + public static Spannable assimilate(Context context, String content) { + if (TextUtils.isEmpty(content)) return null; + content = HTMLUtil.rollbackReplaceTag(content); + Spannable spannable = assimilateOnlyAtUser(context, content); + spannable = assimilateOnlyTag(context, spannable); + spannable = assimilateOnlyLink(context, spannable); + spannable = InputHelper.displayEmoji(context.getResources(), spannable); + return spannable; + } + + /** + * 高亮@User + * + * @param context Context + * @param content string + * @return + */ + public static Spannable highlightAtUser(Context context, CharSequence content) { + return highlightAtUser(context, new SpannableString(content)); + } + + /** + * @param context Context + * @param spannable string + * @return + * @see #highlightAtUser(Context, Spannable) + */ + public static Spannable highlightAtUser(Context context, Spannable spannable) { + String str = spannable.toString(); + Matcher matcher = PatternAtUser.matcher(str); + while (matcher.find()) { + ForegroundColorSpan span = new ForegroundColorSpan(0XFF6888AD); + spannable.setSpan(span, matcher.start(), matcher.end(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + } + return spannable; + } + + /** + * 与 {@link #highlightAtUser(Context, Spannable)} 不同的是这个方法是针对标签包裹的@User + * + * @param context Context + * @param content string + * @return + */ + public static Spannable assimilateOnlyAtUser(final Context context, CharSequence content) { + SpannableStringBuilder builder = new SpannableStringBuilder(content); + Matcher matcher; + while (true) { + matcher = PatternAtUserWithHtml.matcher(builder.toString()); + if (matcher.find()) { + final String group0 = matcher.group(1); // ident + final String group1 = matcher.group(2); // uid + final String group2 = matcher.group(3); // @Nick + final String group3 = matcher.group(4); // Nick + builder.replace(matcher.start(), matcher.end(), group2); + long uid = 0; + try { + uid = group1 == null ? 0 : Integer.valueOf(group1); + } catch (Exception e) { + uid = 0; + } + final long _uid = uid; + ClickableSpan span = new ClickableSpan() { + @Override + public void onClick(View widget) { + if (_uid > 0) { + OtherUserHomeActivity.show(context, _uid); + } else if (!TextUtils.isEmpty(group0)) { + OtherUserHomeActivity.show(context, 0, group0); + } else { + OtherUserHomeActivity.show(context, group3); + } + } + }; + builder.setSpan(span, matcher.start(), matcher.start() + group2.length(), + Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + continue; + } + break; + } + return builder; + } + + /** + * @param context Context + * @param content string + * @return + */ + public static Spannable assimilateOnlyTag(final Context context, CharSequence content) { + return assimilate(content, PatternSoftwareTagWithHtml, 1, 2, new Action1() { + @Override + public void call(String str) { + UIHelper.showUrlRedirect(context, str); + } + }); + } + + /** + * 格式化link链接 + *

    + * 注意: 最好在最后处理这个过程,否则有些需要特殊处理的就会被它格式化掉 + * + * @param context Context + * @param content CharSequence + * @return A spannable object + */ + public static Spannable assimilateOnlyLink(final Context context, CharSequence content) { + return assimilate(content, PatternLinks, 1, 2, new Action1() { + @Override + public void call(String str) { + UIHelper.showUrlRedirect(context, str); + } + }); + } + + public static Spannable assimilateOnlyTeamTask(final Context context, CharSequence content) { + return assimilate(content, PatternTeamTask, 1, 2, new Action1() { + @Override + public void call(String str) { + UIHelper.openInternalBrowser(context, str); + } + }); + } + + public static Spannable clearHtmlTag(CharSequence content) { + SpannableStringBuilder builder = new SpannableStringBuilder(content); + Matcher matcher; + while (true) { + matcher = PatternHtml.matcher(builder.toString()); + if (matcher.find()) { + String str = matcher.group(1); + builder.replace(matcher.start(), matcher.end(), str); + continue; + } + break; + } + return builder; + } + + @Deprecated + public static Spannable assimilateTagAndAtUser(final Context context, String content) { + + // 现将#software#的标签去掉 + content = content.replaceAll("]*>(#[^#@<>\\s]+#)", "$1"); + + Matcher matcher; + Map> maps = new HashMap<>(); + + while (true) { + matcher = PatternAtUserAndLinks.matcher(content); + if (matcher.find()) { + String group1 = matcher.group(1); + String group2 = matcher.group(2); + String group3 = matcher.group(3); + String group4 = matcher.group(4); + if (group1 != null && group2 != null) { + content = matcher.replaceFirst(group2); + maps.put(group1, new Pair<>(matcher.start(), matcher.start() + group2.length())); + } else if (group3 != null && group4 != null) { + content = matcher.replaceFirst(group4); + maps.put(group3, new Pair<>(matcher.start(), matcher.start() + group4.length())); + } else { + content = matcher.replaceFirst(""); + } + continue; + } + break; + } + + Spannable spannable = new SpannableString(content); + + for (final Map.Entry> entry : maps.entrySet()) { + final String substr = entry.getKey(); + final Pair pair = entry.getValue(); + ClickableSpan span = new ClickableSpan() { + @Override + public void onClick(View widget) { + if (substr.startsWith("http://") || substr.startsWith("https://")) { + UIHelper.openInternalBrowser(context, substr); + } else { + OtherUserHomeActivity.show(context, substr); + } + } + + @Override + public void updateDrawState(TextPaint ds) { + ds.setColor(ds.linkColor); + ds.setUnderlineText(false); + } + }; + spannable.setSpan(span, pair.first, pair.second, Spanned.SPAN_INCLUSIVE_INCLUSIVE); + } + + //再处理#software# + matcher = PatternSoftwareTag.matcher(content); + while (matcher.find()) { + final String tag = matcher.group(1); + ClickableSpan span = new ClickableSpan() { + @Override + public void onClick(View widget) { + Bundle bundle = new Bundle(); + bundle.putString("topic", tag); + UIHelper.showSimpleBack(context, SimpleBackPage.TWEET_TOPIC_LIST, bundle); + } + + @Override + public void updateDrawState(TextPaint ds) { + ds.setColor(ds.linkColor); + ds.setUnderlineText(false); + } + }; + spannable.setSpan(span, matcher.start(), matcher.end(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + } + return spannable; + } + + /** + * 本地化处理 + * + * @param content 处理内容 + * @param pattern 匹配规则 + * @param index0 使用的组号 + * @param index1 显示的组号 + * @param action 回调函数 + * @return Spannable + */ + @Deprecated + private static Spannable assimilate(String content, Pattern pattern, int index0, int index1, + final Action1 action) { + Matcher matcher; + Map> maps = new HashMap<>(); + + while (true) { + matcher = pattern.matcher(content); + if (matcher.find()) { + String group0 = matcher.group(index0); + String group1 = matcher.group(index1); + content = matcher.replaceFirst(group1); + maps.put(group0, new Pair<>(matcher.start(), matcher.start() + group1.length())); + continue; + } + break; + } + + Spannable spannable = new SpannableString(content); + + for (final Map.Entry> entry : maps.entrySet()) { + final String substr = entry.getKey(); + final Pair pair = entry.getValue(); + ClickableSpan span = new ClickableSpan() { + @Override + public void onClick(View widget) { + action.call(substr); + } + + @Override + public void updateDrawState(TextPaint ds) { + ds.setColor(ds.linkColor); + ds.setUnderlineText(false); + } + }; + spannable.setSpan(span, pair.first, pair.second, Spanned.SPAN_INCLUSIVE_INCLUSIVE); + } + return spannable; + } + + /** + * 本地化处理 + * + * @param sequence 处理内容 + * @param pattern 匹配规则 + * @param index0 使用的组号 + * @param index1 显示的组号 + * @param action 回调函数 + * @return Spannable + */ + private static Spannable assimilate(CharSequence sequence, Pattern pattern, int index0, + int index1, final Action1 action) { + SpannableStringBuilder builder = new SpannableStringBuilder(sequence); + Matcher matcher; + while (true) { + matcher = pattern.matcher(builder.toString()); + if (matcher.find()) { + final String group0 = matcher.group(index0); + final String group1 = matcher.group(index1); + builder.replace(matcher.start(), matcher.end(), group1); + ClickableSpan span = new ClickableSpan() { + @Override + public void onClick(View widget) { + action.call(group0); + } + }; + builder.setSpan(span, matcher.start(), matcher.start() + group1.length(), + Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + continue; + } + break; + } + return builder; + } + + + public static boolean machPhoneNum(CharSequence phoneNumber) { + + String regex = "^[1][34578][0-9]\\d{8}$"; + // Pattern pattern = Pattern.compile(regex); + // pattern.matcher(phoneNumber).matches(); + + //第二种就是对一种的一种封装 + return Pattern.matches(regex, phoneNumber); + } + + public static boolean machEmail(CharSequence email) { + String regex = "[\\w!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[\\w](?:[\\w-]*[\\w])?"; + return Pattern.matches(regex, email); + } + +} diff --git a/app/src/main/java/net/oschina/app/improve/utils/CacheManager.java b/app/src/main/java/net/oschina/app/improve/utils/CacheManager.java new file mode 100644 index 0000000000000000000000000000000000000000..d349d048ee3d46ad5a9c040c1e680f7f46f2ca37 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/utils/CacheManager.java @@ -0,0 +1,189 @@ +package net.oschina.app.improve.utils; + +import android.content.Context; +import android.text.TextUtils; + +import com.google.gson.Gson; +import com.google.gson.internal.$Gson$Types; + +import net.oschina.app.improve.app.AppOperator; +import net.oschina.common.utils.StreamUtil; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Reader; +import java.io.Serializable; +import java.io.Writer; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.List; + +import static com.google.gson.internal.$Gson$Preconditions.checkArgument; +import static com.google.gson.internal.$Gson$Preconditions.checkNotNull; +import static com.google.gson.internal.$Gson$Types.canonicalize; +import static com.google.gson.internal.$Gson$Types.typeToString; + +/** + * Created by haibin + * on 2016/11/7. + * change by fei + * on 2016/12/9 + */ + +public final class CacheManager { + + public static void saveToJson(Context context, String fileName, List list) { + if (context == null || list == null || list.size() <= 0) + return; + String path = context.getCacheDir() + "/" + fileName + ".json"; + File file = new File(path); + try { + if (!file.exists() && !file.createNewFile()) { + return; + } + save(file, list); + } catch (IOException e) { + e.printStackTrace(); + } + } + + + /** + * save cache file + * + * @param file file + * @param list list + */ + private static void save(File file, List list) { + Writer writer = null; + try { + writer = new FileWriter(file); + AppOperator.getGson().toJson(list, writer); + } catch (IOException e) { + e.printStackTrace(); + } finally { + StreamUtil.close(writer); + } + } + + public static void saveToJson(Context context, String fileName, Object object) { + String json = new Gson().toJson(object); + String path = context.getCacheDir() + "/" + fileName; + File file = new File(path); + FileOutputStream os = null; + try { + if (!file.exists()) + file.createNewFile(); + os = new FileOutputStream(file); + os.write(json.getBytes("utf-8")); + } catch (IOException e) { + e.printStackTrace(); + } finally { + StreamUtil.close(os); + } + } + + public static T readFromJson(Context context, String fileName, Class cla) { + return readJson(context, fileName, cla); + } + + public static T readListJson(Context context, String fileName, Class clx) { + if (clx == null || TextUtils.isEmpty(fileName)) return null; + Type type = getListType(clx); + return readJson(context, fileName, type); + } + + public static T readJson(Context context, String fileName, Type clx) { + if (clx == null) return null; + String path = context.getCacheDir() + "/" + fileName + ".json"; + File file = new File(path); + if (!file.exists()) + return null; + Reader reader = null; + try { + reader = new FileReader(file); + return AppOperator.getGson().fromJson(reader, clx); + } catch (IOException e) { + e.printStackTrace(); + } finally { + StreamUtil.close(reader); + } + return null; + } + + private static Type getListType(Class clx) { + return $Gson$Types.canonicalize((new ParameterizedTypeImpl(null, List.class, clx))); + } + + private static final class ParameterizedTypeImpl implements ParameterizedType, Serializable { + private final Type ownerType; + private final Type rawType; + private final Type[] typeArguments; + + public ParameterizedTypeImpl(Type ownerType, Type rawType, Type... typeArguments) { + // require an owner type if the raw type needs it + if (rawType instanceof Class) { + Class rawTypeAsClass = (Class) rawType; + boolean isStaticOrTopLevelClass = Modifier.isStatic(rawTypeAsClass.getModifiers()) + || rawTypeAsClass.getEnclosingClass() == null; + checkArgument(ownerType != null || isStaticOrTopLevelClass); + } + + this.ownerType = ownerType == null ? null : canonicalize(ownerType); + this.rawType = canonicalize(rawType); + this.typeArguments = typeArguments.clone(); + for (int t = 0; t < this.typeArguments.length; t++) { + checkNotNull(this.typeArguments[t]); + this.typeArguments[t] = canonicalize(this.typeArguments[t]); + } + } + + public Type[] getActualTypeArguments() { + return typeArguments.clone(); + } + + public Type getRawType() { + return rawType; + } + + public Type getOwnerType() { + return ownerType; + } + + @Override + public boolean equals(Object other) { + return other instanceof ParameterizedType + && $Gson$Types.equals(this, (ParameterizedType) other); + } + + @Override + public int hashCode() { + return Arrays.hashCode(typeArguments) + ^ rawType.hashCode() + ^ (ownerType != null ? ownerType.hashCode() : 0); + } + + @Override + public String toString() { + StringBuilder stringBuilder = new StringBuilder(30 * (typeArguments.length + 1)); + stringBuilder.append(typeToString(rawType)); + + if (typeArguments.length == 0) { + return stringBuilder.toString(); + } + + stringBuilder.append("<").append(typeToString(typeArguments[0])); + for (int i = 1; i < typeArguments.length; i++) { + stringBuilder.append(", ").append(typeToString(typeArguments[i])); + } + return stringBuilder.append(">").toString(); + } + + private static final long serialVersionUID = 0; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/utils/DialogHelper.java b/app/src/main/java/net/oschina/app/improve/utils/DialogHelper.java new file mode 100644 index 0000000000000000000000000000000000000000..3b197acdc40e7da1ad63706087b01a6ecf74c3ae --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/utils/DialogHelper.java @@ -0,0 +1,376 @@ +package net.oschina.app.improve.utils; + +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.support.v7.app.AlertDialog; +import android.support.v7.widget.AppCompatEditText; +import android.text.TextUtils; +import android.view.View; + +import net.oschina.app.R; + +/** + * 通用的对话框 + * Created by haibin + * on 2016/11/2. + */ +@SuppressWarnings("all") +public final class DialogHelper { + public static AlertDialog.Builder getDialog(Context context) { + return new AlertDialog.Builder(context, R.style.App_Theme_Dialog_Alert); + } + + /** + * 获取一个普通的消息对话框,没有取消按钮 + */ + public static AlertDialog.Builder getMessageDialog( + Context context, + String title, + String message, + boolean cancelable) { + return getDialog(context) + .setCancelable(cancelable) + .setTitle(title) + .setMessage(message) + .setPositiveButton("确定", null); + } + + /** + * 获取一个普通的消息对话框,没有取消按钮 + */ + public static AlertDialog.Builder getMessageDialog( + Context context, + String title, + String message) { + return getMessageDialog(context, title, message, false); + } + + /** + * 获取一个普通的消息对话框,没有取消按钮 + */ + public static AlertDialog.Builder getMessageDialog(Context context, String message) { + return getMessageDialog(context, "", message, false); + } + + /** + * 获取一个普通的消息对话框,没有取消按钮 + */ + public static AlertDialog.Builder getMessageDialog( + Context context, + String title, + String message, + String positiveText) { + return getDialog(context) + .setCancelable(false) + .setTitle(title) + .setMessage(message) + .setPositiveButton(positiveText, null); + } + + /** + * 获取一个验证对话框 + */ + public static AlertDialog.Builder getConfirmDialog( + Context context, + String title, + String message, + String positiveText, + String negativeText, + boolean cancelable, + DialogInterface.OnClickListener positiveListener, + DialogInterface.OnClickListener negativeListener) { + return getDialog(context) + .setCancelable(cancelable) + .setTitle(title) + .setMessage(message) + .setPositiveButton(positiveText, positiveListener) + .setNegativeButton(negativeText, negativeListener); + } + + /** + * 获取一个验证对话框 + */ + public static AlertDialog.Builder getConfirmDialog( + Context context, String message, + DialogInterface.OnClickListener positiveListener, + DialogInterface.OnClickListener negativeListener) { + return getDialog(context) + .setMessage(message) + .setPositiveButton("确定", positiveListener) + .setNegativeButton("取消", negativeListener); + } + + public static AlertDialog.Builder getSingleChoiceDialog( + Context context, + String title, + String[] arrays, + int selectIndex, + DialogInterface.OnClickListener onClickListener) { + AlertDialog.Builder builder = getDialog(context); + builder.setSingleChoiceItems(arrays, selectIndex, onClickListener); + if (!TextUtils.isEmpty(title)) { + builder.setTitle(title); + } + builder.setNegativeButton("取消", null); + return builder; + } + + + /** + * 获取一个验证对话框,没有点击事件 + */ + public static AlertDialog.Builder getConfirmDialog( + Context context, + String title, + String message, + String positiveText, + String negativeText, + boolean cancelable, + DialogInterface.OnClickListener positiveListener) { + return getConfirmDialog( + context, title, message, positiveText, + negativeText, cancelable, positiveListener, null); + } + + /** + * 获取一个验证对话框,没有点击事件 + */ + public static AlertDialog.Builder getConfirmDialog( + Context context, + String title, + String message, + String positiveText, + String negativeText, + DialogInterface.OnClickListener positiveListener) { + return getConfirmDialog( + context, title, message, positiveText, negativeText, false, positiveListener, null); + } + + + /** + * 获取一个验证对话框,没有点击事件 + */ + public static AlertDialog.Builder getConfirmDialog( + Context context, + String title, + String message, + String positiveText, + String negativeText, + boolean cancelable) { + return getConfirmDialog( + context, title, message, positiveText, negativeText, cancelable, null, null); + } + + /** + * 获取一个验证对话框,没有点击事件 + */ + public static AlertDialog.Builder getConfirmDialog( + Context context, + String message, + String positiveText, + String negativeText, + boolean cancelable) { + return getConfirmDialog(context, "", message, positiveText, negativeText + , cancelable, null, null); + } + + /** + * 获取一个验证对话框,没有点击事件,取消、确定 + */ + public static AlertDialog.Builder getConfirmDialog( + Context context, + String title, + String message, + boolean cancelable) { + return getConfirmDialog(context, title, message, "确定", "取消", cancelable, null, null); + } + + /** + * 获取一个验证对话框,没有点击事件,取消、确定 + */ + public static AlertDialog.Builder getConfirmDialog( + Context context, + String message, + boolean cancelable, + DialogInterface.OnClickListener positiveListener) { + return getConfirmDialog(context, "", message, "确定", "取消", cancelable, positiveListener, null); + } + + /** + * 获取一个验证对话框,没有点击事件,取消、确定 + */ + public static AlertDialog.Builder getConfirmDialog( + Context context, + String message, + DialogInterface.OnClickListener positiveListener) { + return getConfirmDialog(context, "", message, "确定", "取消", positiveListener); + } + + /** + * 获取一个验证对话框,没有点击事件,取消、确定 + */ + public static AlertDialog.Builder getConfirmDialog( + Context context, + String title, + String message) { + return getConfirmDialog(context, title, message, "确定", "取消", false, null, null); + } + + /** + * 获取一个输入对话框 + */ + public static AlertDialog.Builder getInputDialog( + Context context, + String title, + AppCompatEditText editText, + String positiveText, + String negativeText, + boolean cancelable, + DialogInterface.OnClickListener positiveListener, + DialogInterface.OnClickListener negativeListener) { + return getDialog(context) + .setCancelable(cancelable) + .setTitle(title) + .setView(editText) + .setPositiveButton(positiveText, positiveListener) + .setNegativeButton(negativeText, negativeListener); + } + + /** + * 获取一个输入对话框 + */ + public static AlertDialog.Builder getInputDialog( + Context context, String title, + AppCompatEditText editText, + String positiveText, + String negativeText, + boolean cancelable, + DialogInterface.OnClickListener positiveListener) { + return getInputDialog( + context, + title, + editText, + positiveText, + negativeText, + cancelable, + positiveListener, + null); + } + + /** + * 获取一个输入对话框 + */ + public static AlertDialog.Builder getInputDialog( + Context context, + String title, + AppCompatEditText editText, + boolean cancelable, + DialogInterface.OnClickListener positiveListener) { + return getInputDialog(context, title, editText, "确定", "取消" + , cancelable, positiveListener, null); + } + + /** + * 获取一个输入对话框 + */ + public static AlertDialog.Builder getInputDialog( + Context context, String title, AppCompatEditText editText, String positiveText, + boolean cancelable, + DialogInterface.OnClickListener positiveListener, + DialogInterface.OnClickListener negativeListener) { + return getInputDialog( + context, title, editText, positiveText, "取消", cancelable + , positiveListener, negativeListener); + } + + /** + * 获取一个输入对话框 + */ + public static AlertDialog.Builder getInputDialog( + Context context, String title, AppCompatEditText editText, + boolean cancelable, + DialogInterface.OnClickListener positiveListener, + DialogInterface.OnClickListener negativeListener) { + return getInputDialog( + context, title, editText, "确定", "取消", cancelable + , positiveListener, negativeListener); + } + + + /** + * 获取一个等待对话框 + */ + public static ProgressDialog getProgressDialog(Context context) { + return new ProgressDialog(context); + } + + /** + * 获取一个等待对话框 + */ + public static ProgressDialog getProgressDialog(Context context, boolean cancelable) { + ProgressDialog dialog = getProgressDialog(context); + dialog.setCancelable(cancelable); + return dialog; + } + + /** + * 获取一个等待对话框 + */ + public static ProgressDialog getProgressDialog(Context context, String message) { + ProgressDialog dialog = getProgressDialog(context); + dialog.setMessage(message); + return dialog; + } + + /** + * 获取一个等待对话框 + */ + public static ProgressDialog getProgressDialog( + Context context, String title, String message, boolean cancelable) { + ProgressDialog dialog = getProgressDialog(context); + dialog.setCancelable(cancelable); + dialog.setTitle(title); + dialog.setMessage(message); + return dialog; + } + + /** + * 获取一个等待对话框 + */ + public static ProgressDialog getProgressDialog( + Context context, String message, boolean cancelable) { + ProgressDialog dialog = getProgressDialog(context); + dialog.setCancelable(cancelable); + dialog.setMessage(message); + return dialog; + } + + public static AlertDialog.Builder getSelectDialog( + Context context, String title, String[] items, + String positiveText, + DialogInterface.OnClickListener itemListener) { + return getDialog(context) + .setTitle(title) + .setItems(items, itemListener) + .setPositiveButton(positiveText, null); + + } + + public static AlertDialog.Builder getSelectDialog( + Context context, String[] items, + String positiveText, + DialogInterface.OnClickListener itemListener) { + return getDialog(context) + .setItems(items, itemListener) + .setPositiveButton(positiveText, null); + + } + + public static AlertDialog.Builder getSelectDialog(Context context, View view, String positiveText, + DialogInterface.OnClickListener itemListener) { + return getDialog(context) + .setView(view) + .setPositiveButton(positiveText, null); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/utils/PicturesCompressor.java b/app/src/main/java/net/oschina/app/improve/utils/PicturesCompressor.java new file mode 100644 index 0000000000000000000000000000000000000000..16d8eb4a612d292e8757a03b23f98c2dcbec05a9 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/utils/PicturesCompressor.java @@ -0,0 +1,118 @@ +package net.oschina.app.improve.utils; + +import android.graphics.BitmapFactory; + +import net.oschina.common.utils.BitmapUtil; + +import java.io.File; + +import static net.oschina.common.utils.StreamUtil.copyFile; + + +/** + * Created by JuQiu + * on 16/7/21. + */ +@SuppressWarnings("WeakerAccess") +public final class PicturesCompressor { + private PicturesCompressor() { + + } + + public static boolean compressImage(final String srcPath, + final String savePath, + final long targetSize) { + return compressImage(srcPath, savePath, targetSize, 75, 1280, 1280 * 6, null, null, true); + } + + /** + * 压缩图片 + * + * @param srcPath 原图地址 + * @param savePath 存储地址 + * @param maxSize 最大文件地址byte + * @param minQuality 最小质量 + * @param maxWidth 最大宽度 + * @param maxHeight 最大高度 + * @param byteStorage 用于批量压缩时的buffer,不必要为null, + * 需要时,推荐 {{@link BitmapUtil#DEFAULT_BUFFER_SIZE}} + * @param options 批量压缩时复用参数,可调用 {{@link BitmapUtil#createOptions()}} 得到 + * @param exactDecode 是否精确解码, TRUE: 在4.4及其以上机器中能更节约内存 + * @return 是否压缩成功 + */ + public static boolean compressImage(final String srcPath, + final String savePath, + final long maxSize, + final int minQuality, + final int maxWidth, + final int maxHeight, + byte[] byteStorage, + BitmapFactory.Options options, + boolean exactDecode) { + // build source file + final File sourceFile = new File(srcPath); + if (!sourceFile.exists()) + return false; + + // build save file + final File saveFile = new File(savePath); + File saveDir = saveFile.getParentFile(); + if (!saveDir.exists()) { + if (!saveDir.mkdirs()) + return false; + } + + // End clear the out file data + if (saveFile.exists()) { + if (!saveFile.delete()) + return false; + } + + // if the in file size <= maxSize, we can copy to savePath + if (sourceFile.length() <= maxSize && confirmImage(srcPath, options)) { + return copyFile(sourceFile, saveFile); + } + + // Doing + File tempFile = BitmapUtil.Compressor.compressImage(sourceFile, maxSize, minQuality, maxWidth, + maxHeight, byteStorage, options, exactDecode); + + // Rename to out file + return tempFile != null && copyFile(tempFile, saveFile) && tempFile.delete(); + } + + public static boolean confirmImage(String filePath, BitmapFactory.Options opts) { + if (opts == null) opts = BitmapUtil.createOptions(); + opts.inJustDecodeBounds = true; + BitmapFactory.decodeFile(filePath, opts); + String mimeType = opts.outMimeType.toLowerCase(); + return mimeType.contains("jpeg") || mimeType.contains("png") || mimeType.contains("gif"); + } + + public static String verifyPictureExt(String filePath) { + BitmapFactory.Options option = BitmapUtil.createOptions(); + option.inJustDecodeBounds = true; + BitmapFactory.decodeFile(filePath, option); + String mimeType = option.outMimeType.toLowerCase(); + int doIndex = filePath.lastIndexOf(".") + 1; + String ext = filePath.substring(doIndex).toLowerCase(); + if (mimeType.contains("x-ico")) { + //TODO + } else if (mimeType.contains("jpeg")) { + ext = "jpg"; + } else if (mimeType.contains("png")) { + ext = "png"; + } else if (mimeType.contains("webp")) { + //TODO + } else if (mimeType.contains("vnd.wap.wbmp")) { + //TODO + } + String newFilePath = filePath.substring(0, doIndex) + ext; + + if (!filePath.equals(newFilePath)) { + if (new File(filePath).renameTo(new File(newFilePath))) + return newFilePath; + } + return filePath; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/utils/UIUtil.java b/app/src/main/java/net/oschina/app/improve/utils/UIUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..e984db74b96d46a528a7db750811bc1d6bd38814 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/utils/UIUtil.java @@ -0,0 +1,19 @@ +package net.oschina.app.improve.utils; + +import android.content.Context; + +/** + * Created by huanghaibin_dev + * on 2016/7/19. + */ +public class UIUtil { + /** + * 获取状态栏的高度,4.4以下的就不获取了,没必要 + * + * @param context context + * @return statusHeight + */ + public static int getStatusHeight(Context context) { + return 0; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/utils/URLUtils.java b/app/src/main/java/net/oschina/app/improve/utils/URLUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..17dd6c28aec27d81a0394fab663d288ca7903a69 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/utils/URLUtils.java @@ -0,0 +1,253 @@ +package net.oschina.app.improve.utils; + +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.text.TextUtils; + +import net.oschina.app.bean.SimpleBackPage; +import net.oschina.app.improve.detail.activities.BlogDetailActivity; +import net.oschina.app.improve.detail.activities.NewsDetailActivity; +import net.oschina.app.improve.detail.activities.QuestionDetailActivity; +import net.oschina.app.improve.detail.activities.SoftwareDetailActivity; +import net.oschina.app.improve.media.ImageGalleryActivity; +import net.oschina.app.improve.tweet.activities.TweetDetailActivity; +import net.oschina.app.improve.tweet.fragments.TweetFragment; +import net.oschina.app.improve.user.activities.OtherUserHomeActivity; +import net.oschina.app.ui.OSCPhotosActivity; +import net.oschina.app.util.StringUtils; +import net.oschina.app.util.UIHelper; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * 解析URL链接, 如果是站内链接, 用相应的activity打开, 否则用浏览器打开 + * Created by thanatos on 16/9/27. + */ + +public class URLUtils { + + public static final Pattern PATTERN_URL = Pattern.compile( + "(?:http|https)://([^/]+)(.+)" + ); + + public static final Pattern PATTERN_PATH_NEWS = Pattern.compile( + "/news/([0-9]+).*" + ); + + public static final Pattern PATTERN_PATH_SOFTWARE = Pattern.compile( + "/p/([^/]+)" + ); + + public static final Pattern PATTERN_PATH_TOPIC = Pattern.compile( + "/question/tag/(\\w+)" + ); + + public static final Pattern PATTERN_PATH_TWEET_TOPIC = Pattern.compile( + "/tweet-topic/([^/]+)" + ); + + public static final Pattern PATTERN_PATH_QUESTION = Pattern.compile( + "/question/(\\w+)" + ); + + public static final Pattern PATTERN_PATH_USER_BLOG = Pattern.compile( + "/([^/]+)/blog/([0-9]+)" + ); + + public static final Pattern PATTERN_PATH_USER_TWEET = Pattern.compile( + "/([^/]+)/tweet/([0-9]+)" + ); + + public static final Pattern PATTERN_PATH_USER_UID = Pattern.compile( + "/u/([0-9]+)" + ); + + public static final Pattern PATTERN_PATH_USER_SUFFIX = Pattern.compile( + "/([^/]+)" + ); + + public static final Pattern PATTERN_PATH_CITY_EVENT = Pattern.compile( + "/([^/]+)/event/([0-9]+)" + ); + + public static final Pattern PATTERN_PATH_EVENT = Pattern.compile( + "/event/([0-9]+)" + ); + + public static final Pattern PATTERN_IMAGE = Pattern.compile( + ".*?(gif|jpeg|png|jpg|bmp)" + ); + + private static final String PREFIX_IMAGE = "ima-api:action=showImage&data="; + + + /** + * 解析跳转链接, 使用对应应用打开 + * + * @param context Context + * @param uri give me a uri + */ + public static void parseUrl(Context context, String uri) { + if (TextUtils.isEmpty(uri)) return; + + String url = uri; + if (!url.startsWith("http://") && !url.startsWith("https://")) { + url = "https://" + url; + } + try { + url = URLDecoder.decode(url, "UTF-8"); + } catch (UnsupportedEncodingException e) { + // do nothing + } + + Matcher matcher; + + // image url ? + matcher = PATTERN_IMAGE.matcher(url); + if (matcher.matches()) { + ImageGalleryActivity.show(context, url); + return; + } + + matcher = PATTERN_URL.matcher(url); + if (!matcher.find()) { + // other ? + parseNonstandardUrl(context, uri); + return; + } + + // own ? + String host = matcher.group(1); + String path = matcher.group(2); + + if (TextUtils.isEmpty(host) || TextUtils.isEmpty(path)) return; + + long oid = 0; + switch (host) { + case "www.oschina.net": + matcher = PATTERN_PATH_NEWS.matcher(path); + if (matcher.find()) { + oid = StringUtils.toLong(matcher.group(1)); + NewsDetailActivity.show(context, oid); + break; + } + matcher = PATTERN_PATH_SOFTWARE.matcher(path); + if (matcher.find()) { + // https://www.oschina.net/p/parallels-desktop + SoftwareDetailActivity.show(context, matcher.group(1)); + break; + } + matcher = PATTERN_PATH_TOPIC.matcher(path); + if (matcher.find()) { + // TODO replace by new activity + UIHelper.showPostListByTag(context, matcher.group(1)); + break; + } + matcher = PATTERN_PATH_TWEET_TOPIC.matcher(path); + if (matcher.find()) { + // TODO replace by new activity + // https://www.oschina.net/tweet-topic/Navicat+for+Postgresql + Bundle bundle = new Bundle(); + bundle.putInt(TweetFragment.BUNDLE_KEY_REQUEST_CATALOG, TweetFragment.CATALOG_TAG); + bundle.putString(TweetFragment.BUNDLE_KEY_TAG, matcher.group(1)); + UIHelper.showSimpleBack(context, SimpleBackPage.TWEET_TOPIC_LIST, bundle); + break; + } + matcher = PATTERN_PATH_QUESTION.matcher(path); + if (matcher.find()) { + oid = StringUtils.toLong(matcher.group(1).split("_")[1]); + QuestionDetailActivity.show(context, oid); + break; + } + matcher = PATTERN_PATH_EVENT.matcher(path); + if (matcher.find()) { + oid = StringUtils.toLong(matcher.group(1)); + if (oid > 0) { + UIHelper.showEventDetail(context, oid); + break; + } + } + UIHelper.openInternalBrowser(context, url); + break; + case "team.oschina.net": + // TODO team要独立? + UIHelper.openInternalBrowser(context, url); + break; + case "git.oschina.net": + // TODO 如果用户安装了git@osc application, 使用git@osc打开 + UIHelper.openInternalBrowser(context, url); + break; + case "my.oschina.net": + matcher = PATTERN_PATH_USER_BLOG.matcher(path); + if (matcher.find()) { + oid = StringUtils.toLong(matcher.group(2)); + BlogDetailActivity.show(context, oid); + break; + } + matcher = PATTERN_PATH_USER_TWEET.matcher(path); + if (matcher.find()) { + oid = StringUtils.toLong(matcher.group(2)); + TweetDetailActivity.show(context, oid); + break; + } + matcher = PATTERN_PATH_USER_UID.matcher(path); + if (matcher.find()) { + oid = StringUtils.toLong(matcher.group(1)); + OtherUserHomeActivity.show(context, oid); + break; + } + matcher = PATTERN_PATH_USER_SUFFIX.matcher(path); + if (matcher.find()) { + OtherUserHomeActivity.show(context, 0, matcher.group(1)); + break; + } + UIHelper.openInternalBrowser(context, url); + break; + case "city.oschina.net": + matcher = PATTERN_PATH_CITY_EVENT.matcher(url); + if (matcher.find()) { + long eid = StringUtils.toInt(matcher.group(2), 0); + if (eid <= 0) return; + UIHelper.showEventDetail(context, eid); + return; + } + UIHelper.openInternalBrowser(context, url); + break; + default: + // pass + UIHelper.openInternalBrowser(context, url); + } + + } + + public static void parseNonstandardUrl(Context context, String url) { + + if (url.startsWith("mailto:")) { + Uri uri = Uri.parse(url); + Intent intent = new Intent(Intent.ACTION_SENDTO, uri); + context.startActivity(Intent.createChooser(intent, "选择发送应用")); + return; + } + + // image, 我不懂老代码的思路...所以直接copy过来 + if (url.startsWith(PREFIX_IMAGE)) { + String jos = url.substring(PREFIX_IMAGE.length()); + try { + JSONObject json = new JSONObject(jos); + String[] urls = json.getString("urls").split(","); + OSCPhotosActivity.showImagePreview(context, urls[0]); + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + +} diff --git a/app/src/main/java/net/oschina/app/improve/widget/AutoSizeTextView.java b/app/src/main/java/net/oschina/app/improve/widget/AutoSizeTextView.java new file mode 100644 index 0000000000000000000000000000000000000000..de63ceea3b2f7c8ff032d28f5bb7db859e3755a4 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/widget/AutoSizeTextView.java @@ -0,0 +1,69 @@ +package net.oschina.app.improve.widget; + +import android.content.Context; +import android.text.TextPaint; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.widget.TextView; + +/** + * 自适应字体大小的TextView + * + * @author thanatosx + */ +public class AutoSizeTextView extends TextView { + private int mContentWidth; + private float mDefaultTextSize; + private float mMinSize; + + public AutoSizeTextView(Context context) { + this(context, null); + } + + public AutoSizeTextView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public AutoSizeTextView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(attrs, defStyle); + } + + private void init(AttributeSet attrs, int defStyle) { + // Load attributes + mDefaultTextSize = getTextSize(); + // TODO 可配置的mMinSize + mMinSize = 1; + mContentWidth = getWidth() - getPaddingLeft() - getPaddingRight(); + } + + private void resize(CharSequence charSequence) { + // TODO 支持多行 + String text = charSequence.toString(); + if (TextUtils.isEmpty(text) || mContentWidth <= 0) return; + + TextPaint paint = new TextPaint(getPaint()); + paint.setTextSize(mDefaultTextSize); + + float ts = mDefaultTextSize; + for (float mw = paint.measureText(text); ts > mMinSize && mw > mContentWidth; ) { + paint.setTextSize(--ts); + mw = paint.measureText(text); + } + setTextSize(TypedValue.COMPLEX_UNIT_PX, ts); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + mContentWidth = w - getPaddingLeft() - getPaddingRight(); + resize(getText()); + } + + @Override + protected void onTextChanged(CharSequence text, int start, int before, int after) { + super.onTextChanged(text, start, before, after); + resize(text); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/widget/BottomSheetBar.java b/app/src/main/java/net/oschina/app/improve/widget/BottomSheetBar.java new file mode 100644 index 0000000000000000000000000000000000000000..3bf4dde1f3bfb449b8fcbca685994b9d7aebf138 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/widget/BottomSheetBar.java @@ -0,0 +1,232 @@ +package net.oschina.app.improve.widget; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.support.v7.app.AlertDialog; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.Display; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.ImageButton; + +import net.oschina.app.R; +import net.oschina.app.emoji.Emojicon; +import net.oschina.app.emoji.InputHelper; +import net.oschina.app.emoji.OnEmojiClickListener; +import net.oschina.app.improve.emoji.EmojiView; +import net.oschina.app.util.TDevice; + +/** + * 底部弹出评论框 + * Created by haibin + * on 2016/11/10. + *

    + * Changed by fei + * on 2016/11/17 + */ +@SuppressWarnings("unused") +public class BottomSheetBar { + + public static final String TAG = "BottomSheetBar"; + private View mRootView; + private EditText mEditText; + private ImageButton mAtView; + private ImageButton mFaceView; + private CheckBox mSyncToTweetView; + private Context mContext; + private Button mBtnCommit; + private AlertDialog mDialog; + private FrameLayout mFrameLayout; + private EmojiView mEmojiView; + + + private BottomSheetBar(Context context) { + this.mContext = context; + } + + @SuppressLint("InflateParams") + public static BottomSheetBar delegation(Context context) { + BottomSheetBar bar = new BottomSheetBar(context); + bar.mRootView = LayoutInflater.from(context).inflate(R.layout.layout_bottom_sheet_comment_bar, null, false); + bar.initView(); + return bar; + } + + @SuppressWarnings("deprecation") + private void initView() { + mFrameLayout = (FrameLayout) mRootView.findViewById(R.id.fl_face); + mEditText = (EditText) mRootView.findViewById(R.id.et_comment); + mAtView = (ImageButton) mRootView.findViewById(R.id.ib_mention); + mFaceView = (ImageButton) mRootView.findViewById(R.id.ib_face); + mFaceView.setVisibility(View.GONE); + mSyncToTweetView = (CheckBox) mRootView.findViewById(R.id.cb_sync); + if (mFaceView.getVisibility() == View.GONE) { + mSyncToTweetView.setText(R.string.send_tweet); + } + mBtnCommit = (Button) mRootView.findViewById(R.id.btn_comment); + mBtnCommit.setEnabled(false); + + //mDialog = new Dialog(mContext, R.style.Comment_Dialog); + AlertDialog.Builder builder = new AlertDialog.Builder(mContext, R.style.share_dialog); + builder.setView(mRootView); + mDialog = builder.create(); + Window window = mDialog.getWindow(); + + if (window != null) { + window.setGravity(Gravity.BOTTOM); + WindowManager m = window.getWindowManager(); + Display d = m.getDefaultDisplay(); + WindowManager.LayoutParams p = window.getAttributes(); + p.width = d.getWidth(); + window.setAttributes(p); + } + + mDialog.setOnDismissListener(new DialogInterface.OnDismissListener() { + @Override + public void onDismiss(DialogInterface dialog) { + + mRootView.postDelayed(new Runnable() { + @Override + public void run() { + TDevice.hideSoftKeyboard(mEditText); + } + }, 10); + mFrameLayout.setVisibility(View.GONE); + } + }); + + mEditText.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + mBtnCommit.setEnabled(s.length() > 0); + } + }); + } + + public void hideSyncAction() { + mSyncToTweetView.setVisibility(View.INVISIBLE); + mSyncToTweetView.setText(null); + } + + /** + * 默认显示的 + */ + public void showSyncAction() { + mSyncToTweetView.setVisibility(View.VISIBLE); + mSyncToTweetView.setText(R.string.send_tweet); + } + + public void showEmoji() { + mSyncToTweetView.setText(R.string.tweet_publish_title); + mFaceView.setVisibility(View.VISIBLE); + mFaceView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (mEmojiView == null) { + mEmojiView = new EmojiView(mContext, mEditText); + mEmojiView.setListener(new OnEmojiClickListener() { + @Override + public void onDeleteButtonClick(View v) { + InputHelper.backspace(mEditText); + } + + @Override + public void onEmojiClick(Emojicon v) { + + } + }); + mFrameLayout.addView(mEmojiView); + } + TDevice.closeKeyboard(mEditText); + mFrameLayout.setVisibility(View.VISIBLE); + + } + }); + + mEditText.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mFrameLayout.setVisibility(View.GONE); + } + }); + } + + public void show(String hint) { + mDialog.show(); + if (!"添加评论".equals(hint)) { + mEditText.setHint(hint + " "); + } + //Selection.setSelection(mEditText.getText(), mEditText.length()); + mRootView.postDelayed(new Runnable() { + @Override + public void run() { + TDevice.showSoftKeyboard(mEditText); + } + }, 50); + } + + public void dismiss() { + TDevice.closeKeyboard(mEditText); + mDialog.dismiss(); + } + + public void setMentionListener(View.OnClickListener listener) { + mAtView.setOnClickListener(listener); + } + + public void setFaceListener(View.OnClickListener listener) { + mFaceView.setOnClickListener(listener); + } + + public void setCommitListener(View.OnClickListener listener) { + mBtnCommit.setOnClickListener(listener); + } + + public void handleSelectFriendsResult(Intent data) { + String names[] = data.getStringArrayExtra("names"); + if (names != null && names.length > 0) { + String text = ""; + for (String n : names) { + text += "@" + n + " "; + } + mEditText.getText().insert(mEditText.getSelectionEnd(), text); + } + } + + public EditText getEditText() { + return mEditText; + } + + public String getCommentText() { + return mEditText.getText().toString().trim(); + } + + public Button getBtnCommit() { + return mBtnCommit; + } + + public boolean isSyncToTweet() { + return mSyncToTweetView != null && mSyncToTweetView.isChecked(); + } + +} diff --git a/app/src/main/java/net/oschina/app/improve/widget/DetailAboutView.java b/app/src/main/java/net/oschina/app/improve/widget/DetailAboutView.java new file mode 100644 index 0000000000000000000000000000000000000000..4410a0e3335c2f6732e38dc5bb23e9e5e548d9fd --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/widget/DetailAboutView.java @@ -0,0 +1,99 @@ +package net.oschina.app.improve.widget; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.support.annotation.Nullable; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; + +import net.oschina.app.R; +import net.oschina.app.improve.bean.simple.About; +import net.oschina.app.util.UIHelper; + +import java.util.List; + +/** + * Created by JuQiu + * on 16/6/12. + */ + +public class DetailAboutView extends LinearLayout { + private int mDefaultType; + private LinearLayout mLayAbouts; + private TextView mTitle; + + public DetailAboutView(Context context) { + super(context); + init(); + } + + public DetailAboutView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + init(); + } + + public DetailAboutView(Context context, @Nullable AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + private void init() { + setOrientation(VERTICAL); + LayoutInflater inflater = LayoutInflater.from(getContext()); + View inflate = inflater.inflate(R.layout.lay_detail_about_layout, this, true); + + mTitle = (TextView) inflate.findViewById(R.id.tv_blog_detail_about); + mLayAbouts = (LinearLayout) findViewById(R.id.lay_blog_detail_about); + } + + /** + * set title + * + * @param title string + */ + public void setTitle(String title) { + mTitle.setText(title); + } + + public void setAbout(List abouts, int defaultType) { + this.mDefaultType = defaultType; + final LayoutInflater inflater = LayoutInflater.from(getContext()); + if (abouts != null && abouts.size() > 0) { + boolean clearLine = true; + for (final About about : abouts) { + if (about == null) + continue; + @SuppressLint("InflateParams") View lay = inflater.inflate(R.layout.lay_blog_detail_about, null, false); + ((TextView) lay.findViewById(R.id.tv_title)).setText(about.getTitle()); + + View layInfo = lay.findViewById(R.id.lay_info_view_comment); + layInfo.findViewById(R.id.iv_info_view).setVisibility(GONE); + ((TextView) layInfo.findViewById(R.id.tv_info_view)).setVisibility(GONE);//setText(String.valueOf(about.getViewCount())); + ((TextView) layInfo.findViewById(R.id.tv_info_comment)).setText(String.valueOf(about.getCommentCount())); + + if (clearLine) { + clearLine = false; + lay.findViewById(R.id.line).setVisibility(View.INVISIBLE); + } + + lay.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + int type = mDefaultType; + if (about.getType() != 0) { + type = about.getType(); + } + UIHelper.showDetail(v.getContext(), type, about.getId(), null); + } + }); + + mLayAbouts.addView(lay, 0); + } + } else { + setVisibility(View.GONE); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/widget/FlowLayout.java b/app/src/main/java/net/oschina/app/improve/widget/FlowLayout.java new file mode 100644 index 0000000000000000000000000000000000000000..e7b4a448718dc09914fab1016b6f00089f375384 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/widget/FlowLayout.java @@ -0,0 +1,150 @@ +package net.oschina.app.improve.widget; + +import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; + +import net.oschina.app.R; + +/** + * Created by JuQiu + * on 16/6/24. + * 自动换行布局 + *

    + * {@link #mVerticalSpacing 每一行之间的间距} + * {@link #mHorizontalSpacing 水平方向控件之间的间距} + */ +public class FlowLayout extends ViewGroup { + private float mVerticalSpacing; + private float mHorizontalSpacing; + + public FlowLayout(Context context) { + super(context); + init(null, 0, 0); + } + + public FlowLayout(Context context, AttributeSet attrs) { + super(context, attrs); + init(attrs, 0, 0); + } + + private void init(AttributeSet attrs, int defStyleAttr, int defStyleRes) { + final Context context = getContext(); + final Resources resources = getResources(); + final float density = resources.getDisplayMetrics().density; + + int vSpace = (int) (4 * density); + int hSpace = vSpace; + + if (attrs != null) { + // Load attributes + final TypedArray a = context.obtainStyledAttributes( + attrs, R.styleable.FlowLayout, defStyleAttr, defStyleRes); + + // Load clip touch corner radius + vSpace = a.getDimensionPixelOffset(R.styleable.FlowLayout_verticalSpace, vSpace); + hSpace = a.getDimensionPixelOffset(R.styleable.FlowLayout_horizontalSpace, hSpace); + a.recycle(); + } + + setVerticalSpacing(vSpace); + setHorizontalSpacing(hSpace); + } + + public void setHorizontalSpacing(float pixelSize) { + mHorizontalSpacing = pixelSize; + } + + public void setVerticalSpacing(float pixelSize) { + mVerticalSpacing = pixelSize; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int selfWidth = resolveSize(0, widthMeasureSpec); + + int paddingLeft = getPaddingLeft(); + int paddingTop = getPaddingTop(); + int paddingRight = getPaddingRight(); + int paddingBottom = getPaddingBottom(); + + int childLeft = paddingLeft; + int childTop = paddingTop; + int lineHeight = 0; + final int contentWidth = selfWidth - paddingRight - paddingLeft; + + //通过计算每一个子控件的高度,得到自己的高度 + for (int i = 0, childCount = getChildCount(); i < childCount; ++i) { + View childView = getChildAt(i); + LayoutParams childLayoutParams = childView.getLayoutParams(); + childView.measure( + getChildMeasureSpec(widthMeasureSpec, paddingLeft + paddingRight, + childLayoutParams.width), + getChildMeasureSpec(heightMeasureSpec, paddingTop + paddingBottom, + childLayoutParams.height)); + int childWidth = childView.getMeasuredWidth(); + int childHeight = childView.getMeasuredHeight(); + lineHeight = Math.max(childHeight, lineHeight); + + childLeft += childWidth; + if (childLeft > contentWidth) { + childLeft = childWidth; + childTop += mVerticalSpacing + lineHeight; + lineHeight = childHeight; + } else { + childLeft += mHorizontalSpacing; + } + } + + int wantedHeight = childTop + lineHeight + paddingBottom; + wantedHeight = resolveSize(wantedHeight, heightMeasureSpec); + setMeasuredDimension(selfWidth, wantedHeight); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + float childCount = getChildCount(); + if (childCount > 0) { + int paddingLeft = getPaddingLeft(); + int paddingTop = getPaddingTop(); + + if (childCount == 1) { + View childView = getChildAt(0); + int childWidth = childView.getMeasuredWidth(); + int childHeight = childView.getMeasuredHeight(); + childView.layout(paddingLeft, paddingTop, paddingLeft + childWidth, paddingTop + childHeight); + } else { + int mWidth = r - l; + int paddingRight = getPaddingRight(); + + int lineHeight = 0; + int childLeft = paddingLeft; + int childTop = paddingTop; + + for (int i = 0; i < childCount; ++i) { + View childView = getChildAt(i); + + if (childView.getVisibility() == View.GONE) { + continue; + } + + int childWidth = childView.getMeasuredWidth(); + int childHeight = childView.getMeasuredHeight(); + + lineHeight = Math.max(childHeight, lineHeight); + + if (childLeft + childWidth + paddingRight > mWidth) { + childLeft = paddingLeft; + childTop += mVerticalSpacing + lineHeight; + lineHeight = childHeight; + } + childView.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight); + childLeft += childWidth + mHorizontalSpacing; + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/oschina/app/improve/widget/FragmentPagerAdapter.java b/app/src/main/java/net/oschina/app/improve/widget/FragmentPagerAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..9c6e15d625c5ac13775a87b5a49db1c4f423a61c --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/widget/FragmentPagerAdapter.java @@ -0,0 +1,119 @@ +package net.oschina.app.improve.widget; + +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; +import android.support.v4.view.PagerAdapter; +import android.view.View; +import android.view.ViewGroup; + +import net.oschina.app.util.TLog; + +/** + * 我们不希望维持Fragment的状态,因为可能活动的Tab会很多,所以既不能用 + * {@link android.support.v4.app.FragmentPagerAdapter}, 因为它通过{@link FragmentTransaction#add(Fragment, String)}, + * {@link FragmentTransaction#attach(Fragment)}和{@link FragmentTransaction#detach(Fragment)}的方式, + * 状态由{@link Fragment}自己维护,也不能用{@link android.support.v4.app.FragmentStatePagerAdapter}, 因为 + * 它通过{@link FragmentTransaction#add(Fragment, String)}和{@link FragmentTransaction#remove(Fragment)} + * 的方式,有两个集合保存加入的{@link Fragment}以及它们的状态 + *

    + *

    Created by thanatosx on 2016/11/9. + */ +@SuppressWarnings("all") +public abstract class FragmentPagerAdapter extends PagerAdapter { + + private final FragmentManager mFragmentManager; + private FragmentTransaction mCurTransaction; + private Fragment mCurrentPrimaryItem; + + public FragmentPagerAdapter(FragmentManager fm) { + mFragmentManager = fm; + } + + /** + * Return the fragment associated with a specified position + * + * @param position the position + * @return {@link Fragment} + */ + public abstract Fragment getItem(int position); + + @Override + public void startUpdate(ViewGroup container) { + if (container.getId() == View.NO_ID) { + throw new IllegalStateException("ViewPager with adapter " + this + + " requires a view id"); + } + } + + @Override + public Object instantiateItem(ViewGroup container, int position) { + if (mCurTransaction == null) { + mCurTransaction = mFragmentManager.beginTransaction(); + } + + Fragment fragment = getItem(position); + TLog.i("oschina", "Adding fragment item #" + position + ": f=" + fragment); + fragment.setMenuVisibility(false); + fragment.setUserVisibleHint(false); + mCurTransaction.add(container.getId(), fragment, + makeFragmentName(container.getId(), getItemId(position))); + return fragment; + } + + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + Fragment fragment = (Fragment) object; + + if (mCurTransaction == null) { + mCurTransaction = mFragmentManager.beginTransaction(); + } + TLog.i("oschina", "Removing fragment #" + position + ": f=" + fragment + + " v=" + fragment.getView()); + mCurTransaction.remove(fragment); + } + + @Override + public void setPrimaryItem(ViewGroup container, int position, Object object) { + Fragment fragment = (Fragment) object; + if (fragment != mCurrentPrimaryItem) { + if (mCurrentPrimaryItem != null) { + mCurrentPrimaryItem.setMenuVisibility(false); + mCurrentPrimaryItem.setUserVisibleHint(false); + } + if (fragment != null) { + fragment.setMenuVisibility(true); + fragment.setUserVisibleHint(true); + } + mCurrentPrimaryItem = fragment; + } + } + + @Override + public void finishUpdate(ViewGroup container) { + /*if (mCurTransaction != null) { + mCurTransaction.commitNowAllowingStateLoss(); + mCurTransaction = null; + }*/ + } + + public void commitUpdate() { + if (mCurTransaction != null) { + mCurTransaction.commitNowAllowingStateLoss(); + mCurTransaction = null; + } + } + + @Override + public boolean isViewFromObject(View view, Object object) { + return ((Fragment) object).getView() == view; + } + + protected String makeFragmentName(int viewId, long id) { + return "android:switcher:" + viewId + ":" + id; + } + + protected long getItemId(int position) { + return position; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/widget/OWebView.java b/app/src/main/java/net/oschina/app/improve/widget/OWebView.java new file mode 100644 index 0000000000000000000000000000000000000000..e5936e42dccf5a2f773e6866806324c0a39f6072 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/widget/OWebView.java @@ -0,0 +1,281 @@ +package net.oschina.app.improve.widget; + +import android.annotation.SuppressLint; +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.Context; +import android.graphics.Bitmap; +import android.net.http.SslError; +import android.os.Build; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.webkit.JavascriptInterface; +import android.webkit.SslErrorHandler; +import android.webkit.WebSettings; +import android.webkit.WebView; +import android.webkit.WebViewClient; + +import net.oschina.app.AppConfig; +import net.oschina.app.AppContext; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.media.ImageGalleryActivity; +import net.oschina.app.interf.OnWebViewImageListener; +import net.oschina.app.util.StringUtils; +import net.oschina.app.util.TDevice; +import net.oschina.app.util.TLog; +import net.oschina.app.util.UIHelper; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Created by JuQiu + * on 16/6/24. + */ + +public class OWebView extends WebView { + public OWebView(Context context) { + super(context); + init(); + } + + public OWebView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public OWebView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + public OWebView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + init(); + } + + public OWebView(Context context, AttributeSet attrs, int defStyleAttr, boolean privateBrowsing) { + super(context, attrs, defStyleAttr, privateBrowsing); + init(); + } + + @SuppressLint({"AddJavascriptInterface", "SetJavaScriptEnabled"}) + private void init() { + setClickable(false); + setFocusable(false); + + setHorizontalScrollBarEnabled(false); + + WebSettings settings = getSettings(); + settings.setDefaultFontSize(14); + settings.setSupportZoom(false); + settings.setBuiltInZoomControls(false); + settings.setDisplayZoomControls(false); + settings.setJavaScriptEnabled(true); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + addJavascriptInterface(new OnWebViewImageListener() { + @Override + @JavascriptInterface + public void showImagePreview(String bigImageUrl) { + if (bigImageUrl != null && !StringUtils.isEmpty(bigImageUrl)) { + ImageGalleryActivity.show(getContext(), bigImageUrl); + } + } + }, "mWebViewImageListener"); + } + } + + public void loadDetailDataAsync(final String content, Runnable finishCallback) { + this.setWebViewClient(new OWebClient(finishCallback)); + Context context = getContext(); + if (context != null && context instanceof Activity) { + final Activity activity = (Activity) context; + AppOperator.runOnThread(new Runnable() { + @Override + public void run() { + final String body = setupWebContent(content, true, true, ""); + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + //loadData(body, "text/html; charset=UTF-8", null); + loadDataWithBaseURL("", body, "text/html", "UTF-8", ""); + } + }); + } + }); + } else { + TLog.e(OWebView.class.getName(), "loadDetailDataAsync error, the Context isn't ok"); + } + } + + + public void loadTweetDataAsync(final String content, Runnable finishCallback) { + this.setWebViewClient(new OWebClient(finishCallback)); + Context context = getContext(); + if (context != null && context instanceof Activity) { + final Activity activity = (Activity) context; + AppOperator.runOnThread(new Runnable() { + @Override + public void run() { + final String body = setupWebContent(content, ""); + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + //loadData(body, "text/html; charset=UTF-8", null); + loadDataWithBaseURL("", body, "text/html", "UTF-8", ""); + } + }); + } + }); + } else { + TLog.e(OWebView.class.getName(), "loadDetailDataAsync error, the Context isn't ok"); + } + } + + @Override + public void destroy() { + setWebViewClient(null); + + WebSettings settings = getSettings(); + settings.setJavaScriptEnabled(false); + + removeJavascriptInterface("mWebViewImageListener"); + removeAllViewsInLayout(); + + removeAllViews(); + //clearCache(true); + + super.destroy(); + } + + private static String setupWebContent(String content, String style) { + if (TextUtils.isEmpty(content) || TextUtils.isEmpty(content.trim())) + return ""; + if (AppContext.get(AppConfig.KEY_LOAD_IMAGE, true) + || TDevice.isWifiOpen()) { + Pattern pattern = Pattern.compile("]+src\\s*=\\s*[\"\']([^\"\']*)[\"\'](\\s*data-url\\s*=\\s*[\"\']([^\"\']*)[\"\'])*"); + Matcher matcher = pattern.matcher(content); + while (matcher.find()) { + String snippet = String.format( + "]*)\\s*>", ""); + } + return String.format( + "" + + "" + + "" + + "" + + "" + + "" + + "

    " + + "%s" + + "
    " + + "" + + "" + , style == null ? "" : style, content); + } + + private static String setupWebContent(String content, boolean isShowHighlight, boolean isShowImagePreview, String css) { + if (TextUtils.isEmpty(content) || TextUtils.isEmpty(content.trim())) + return ""; + + // 读取用户设置:是否加载文章图片--默认有wifi下始终加载图片 + if (AppContext.get(AppConfig.KEY_LOAD_IMAGE, true) + || TDevice.isWifiOpen()) { + // 过滤掉 img标签的width,height属性 + content = content.replaceAll("(]*?)\\s+width\\s*=\\s*\\S+", "$1"); + content = content.replaceAll("(]*?)\\s+height\\s*=\\s*\\S+", "$1"); + + // 添加点击图片放大支持 + if (isShowImagePreview) { + // TODO 用一个正则就搞定?? + content = content.replaceAll("]+src=\"([^\"\'\\s]+)\"[^>]*>", + ""); + content = content.replaceAll( + "]*href=[\"\']([^\"\']+)[\"\'][^<>]*>\\s*]*/>\\s*", + ""); + } + } else { + // 过滤掉 img标签 + content = content.replaceAll("<\\s*img\\s+([^>]*)\\s*/>", ""); + } + + // 过滤table的内部属性 + content = content.replaceAll("(]*?)\\s+border\\s*=\\s*\\S+", "$1"); + content = content.replaceAll("(]*?)\\s+cellspacing\\s*=\\s*\\S+", "$1"); + content = content.replaceAll("(]*?)\\s+cellpadding\\s*=\\s*\\S+", "$1"); + + + return String.format( + "" + + "" + + "" + + (isShowHighlight ? "" : "") + + (isShowHighlight ? "" : "") + + "" + + "%s" + + "" + + "" + + "
    " + + "%s" + + "
    " + + (isShowHighlight ? "" : "") + + (isShowHighlight ? "" : "") + + (isShowHighlight ? "" : "") + + "" + + "" + , (css == null ? "" : css), content); + } + + private static class OWebClient extends WebViewClient implements Runnable { + private Runnable mFinishCallback; + private boolean mDone = false; + + OWebClient(Runnable finishCallback) { + super(); + mFinishCallback = finishCallback; + } + + @Override + public void onPageStarted(WebView view, String url, Bitmap favicon) { + super.onPageStarted(view, url, favicon); + mDone = false; + // 当webview加载2秒后强制回馈完成 + view.postDelayed(this, 2800); + } + + @Override + public void onPageFinished(WebView view, String url) { + super.onPageFinished(view, url); + run(); + } + + @Override + public synchronized void run() { + if (!mDone) { + mDone = true; + if (mFinishCallback != null) mFinishCallback.run(); + } + } + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + UIHelper.showUrlRedirect(view.getContext(), url); + return true; + } + + @Override + public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { + // TODO + handler.cancel(); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/widget/RecyclerRefreshLayout.java b/app/src/main/java/net/oschina/app/improve/widget/RecyclerRefreshLayout.java new file mode 100644 index 0000000000000000000000000000000000000000..41d5761921f9ee4c99fbac676a59a394b4e97ea5 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/widget/RecyclerRefreshLayout.java @@ -0,0 +1,226 @@ +package net.oschina.app.improve.widget; + +import android.content.Context; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.StaggeredGridLayoutManager; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; + +import net.oschina.app.R; + +/** + * 下拉刷新上拉加载控件,目前适用于RecyclerView + * Created by huanghaibin on 16-5-3. + */ +public class RecyclerRefreshLayout extends SwipeRefreshLayout implements SwipeRefreshLayout.OnRefreshListener { + private RecyclerView mRecycleView; + + private int mTouchSlop; + + private SuperRefreshLayoutListener listener; + + private boolean mIsOnLoading = false; + + private boolean mCanLoadMore = true; + + private boolean mHasMore = true; + + private int mYDown; + + private int mLastY; + + public RecyclerRefreshLayout(Context context) { + this(context, null); + } + + public RecyclerRefreshLayout(Context context, AttributeSet attrs) { + super(context, attrs); + mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); + setOnRefreshListener(this); + } + + + @Override + public void onRefresh() { + if (listener != null && !mIsOnLoading) { + listener.onRefreshing(); + } else + setRefreshing(false); + } + + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + // 初始化ListView对象 + if (mRecycleView == null) { + getRecycleView(); + } + } + + /** + * 获取RecyclerView,后续支持AbsListView + */ + private void getRecycleView() { + if (getChildCount() > 0) { + View childView = getChildAt(0); + if (!(childView instanceof RecyclerView)) { + childView = findViewById(R.id.recyclerView); + } + if (childView != null && childView instanceof RecyclerView) { + mRecycleView = (RecyclerView) childView; + mRecycleView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + + } + + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + if (canLoad() && mCanLoadMore) { + loadData(); + } + } + }); + } + } + } + + @Override + public boolean dispatchTouchEvent(MotionEvent event) { + final int action = event.getAction(); + switch (action) { + case MotionEvent.ACTION_DOWN: + mYDown = (int) event.getRawY(); + break; + case MotionEvent.ACTION_MOVE: + mLastY = (int) event.getRawY(); + break; + default: + break; + } + return super.dispatchTouchEvent(event); + } + + /** + * 是否可以加载更多, 条件是到了最底部 + * + * @return isCanLoad + */ + private boolean canLoad() { + return isScrollBottom() && !mIsOnLoading && isPullUp() && mHasMore; + } + + /** + * 如果到了最底部,而且是上拉操作.那么执行onLoad方法 + */ + private void loadData() { + if (listener != null) { + setOnLoading(true); + listener.onLoadMore(); + } + } + + /** + * 是否是上拉操作 + * + * @return isPullUp + */ + private boolean isPullUp() { + return (mYDown - mLastY) >= mTouchSlop; + } + + /** + * 设置正在加载 + * + * @param loading 设置正在加载 + */ + public void setOnLoading(boolean loading) { + mIsOnLoading = loading; + if (!mIsOnLoading) { + mYDown = 0; + mLastY = 0; + } + } + + /** + * 判断是否到了最底部 + */ + private boolean isScrollBottom() { + return (mRecycleView != null && mRecycleView.getAdapter() != null) + && getLastVisiblePosition() == (mRecycleView.getAdapter().getItemCount() - 1); + } + + /** + * 加载结束记得调用 + */ + public void onComplete() { + setOnLoading(false); + setRefreshing(false); + mHasMore = true; + } + + /** + * 是否可加载更多 + * + * @param mCanLoadMore 是否可加载更多 + */ + public void setCanLoadMore(boolean mCanLoadMore) { + this.mCanLoadMore = mCanLoadMore; + } + + /** + * 获取RecyclerView可见的最后一项 + * + * @return 可见的最后一项position + */ + public int getLastVisiblePosition() { + int position; + if (mRecycleView.getLayoutManager() instanceof LinearLayoutManager) { + position = ((LinearLayoutManager) mRecycleView.getLayoutManager()).findLastVisibleItemPosition(); + } else if (mRecycleView.getLayoutManager() instanceof GridLayoutManager) { + position = ((GridLayoutManager) mRecycleView.getLayoutManager()).findLastVisibleItemPosition(); + } else if (mRecycleView.getLayoutManager() instanceof StaggeredGridLayoutManager) { + StaggeredGridLayoutManager layoutManager = (StaggeredGridLayoutManager) mRecycleView.getLayoutManager(); + int[] lastPositions = layoutManager.findLastVisibleItemPositions(new int[layoutManager.getSpanCount()]); + position = getMaxPosition(lastPositions); + } else { + position = mRecycleView.getLayoutManager().getItemCount() - 1; + } + return position; + } + + /** + * 获得最大的位置 + * + * @param positions 获得最大的位置 + * @return 获得最大的位置 + */ + private int getMaxPosition(int[] positions) { + int maxPosition = Integer.MIN_VALUE; + for (int position : positions) { + maxPosition = Math.max(maxPosition, position); + } + return maxPosition; + } + + /** + * 添加加载和刷新 + * + * @param listener add the listener for SuperRefreshLayout + */ + public void setSuperRefreshLayoutListener(SuperRefreshLayoutListener listener) { + this.listener = listener; + } + + public interface SuperRefreshLayoutListener { + void onRefreshing(); + + void onLoadMore(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/widget/RippleIntroView.java b/app/src/main/java/net/oschina/app/improve/widget/RippleIntroView.java new file mode 100644 index 0000000000000000000000000000000000000000..ab5236dc793534a191f5c39ba50fcfd9e3d009a7 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/widget/RippleIntroView.java @@ -0,0 +1,127 @@ +package net.oschina.app.improve.widget; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.util.AttributeSet; +import android.view.View; +import android.widget.RelativeLayout; + +/** + * Created by thanatosx on 2016/11/15. + */ + +public class RippleIntroView extends RelativeLayout implements Runnable { + + private int mMaxRadius = 70; + private int mInterval = 20; + private int count = 0; + + private Bitmap mCacheBitmap; + private Paint mRipplePaint; + private Paint mCirclePaint; + private Path mArcPath; + + public RippleIntroView(Context context) { + this(context, null); + } + + public RippleIntroView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public RippleIntroView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + private void init() { + mRipplePaint = new Paint(); + mRipplePaint.setAntiAlias(true); + mRipplePaint.setStyle(Paint.Style.STROKE); + mRipplePaint.setColor(Color.WHITE); + mRipplePaint.setStrokeWidth(2.f); + + mCirclePaint = new Paint(); + mCirclePaint.setAntiAlias(true); + mCirclePaint.setStyle(Paint.Style.FILL); + mCirclePaint.setColor(Color.WHITE); + + mArcPath = new Path(); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + if (mCacheBitmap != null) { + mCacheBitmap.recycle(); + mCacheBitmap = null; + } + } + + @Override + protected void onDraw(Canvas canvas) { + // 我知道直接getChildAt(int)很挫,但是我就是要这么简单粗暴! + View mPlusChild = getChildAt(0); + View mRefsChild = getChildAt(1); + if (mPlusChild == null || mRefsChild == null) return; + + final int pw = mPlusChild.getWidth(); + final int ph = mPlusChild.getHeight(); + + final int fw = mRefsChild.getWidth(); + final int fh = mRefsChild.getHeight(); + + if (pw == 0 || ph == 0) return; + + final float px = mPlusChild.getX() + pw / 2; + final float py = mPlusChild.getY() + ph / 2; + final float fx = mRefsChild.getX(); + final float fy = mRefsChild.getY(); + final int rw = pw / 2; + final int rh = ph / 2; + + if (mCacheBitmap == null) { + mCacheBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); + Canvas cv = new Canvas(mCacheBitmap); + super.onDraw(cv); + + mArcPath.reset(); + mArcPath.moveTo(px, py + rh + mInterval); + mArcPath.quadTo(px, fy - mInterval, fx + fw * 0.618f, fy - mInterval); + mRipplePaint.setAlpha(255); + cv.drawPath(mArcPath, mRipplePaint); + cv.drawCircle(px, py + rh + mInterval, 6, mCirclePaint); + } + + canvas.drawBitmap(mCacheBitmap, 0, 0, mCirclePaint); + + int save = canvas.save(); + for (int step = count; step <= mMaxRadius; step += mInterval) { + mRipplePaint.setAlpha(255 * (mMaxRadius - step) / mMaxRadius); + canvas.drawCircle(px, py, (float) (rw + step), mRipplePaint); + } + canvas.restoreToCount(save); + postDelayed(this, 80); + } + + @Override + public void run() { + removeCallbacks(this); + count += 2; + count %= mInterval; + invalidate(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + if (mCacheBitmap != null) { + mCacheBitmap.recycle(); + mCacheBitmap = null; + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/widget/SimplexToast.java b/app/src/main/java/net/oschina/app/improve/widget/SimplexToast.java new file mode 100644 index 0000000000000000000000000000000000000000..0c7b8a65ff0b7783eca1f912bfca28d951667646 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/widget/SimplexToast.java @@ -0,0 +1,72 @@ +package net.oschina.app.improve.widget; + +import android.content.Context; +import android.view.Gravity; +import android.widget.Toast; + +/** + * 以后请用这个吐司,谢谢!!! + *

    + *

    + * {@link Toast}的创建都是要inflate一个layout, findViewById之类的 + * 将一个吐司单例化,并且作防止频繁点击的处理。 + *

    + *

    + * Created by thanatosx on 2016/11/15. + */ +@SuppressWarnings("all") +public class SimplexToast { + + private static Toast mToast; + private static long nextTimeMillis; + private static int yOffset; + + private SimplexToast(Context context) { + + } + + public static Toast init(Context context) { + if (context == null) { + throw new IllegalArgumentException("Context should not be null!!!"); + } + if (mToast == null) { + mToast = Toast.makeText(context, null, Toast.LENGTH_SHORT); + yOffset = mToast.getYOffset(); + } + mToast.setDuration(Toast.LENGTH_SHORT); + mToast.setGravity(Gravity.BOTTOM, 0, yOffset); + mToast.setMargin(0, 0); + return mToast; + } + + public static void show(String content) { + show(content, Toast.LENGTH_SHORT); + } + + public static void show(String content, int duration) { + show(null, content, Gravity.BOTTOM, duration); + } + + public static void show(Context context, int rid) { + show(context, context.getResources().getString(rid)); + } + + public static void show(Context context, String content) { + show(context, content, Gravity.BOTTOM); + } + + public static void show(Context context, String content, int gravity) { + show(context, content, gravity, Toast.LENGTH_SHORT); + } + + public static void show(Context context, String content, int gravity, int duration) { + long current = System.currentTimeMillis(); + if (current < nextTimeMillis) return; + if (mToast == null) init(context.getApplicationContext()); + mToast.setText(content); + mToast.setDuration(duration); + mToast.setGravity(gravity, 0, yOffset); + nextTimeMillis = current + (duration == Toast.LENGTH_LONG ? 3500 : 2000); + mToast.show(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/widget/SolarSystemView.java b/app/src/main/java/net/oschina/app/improve/widget/SolarSystemView.java new file mode 100644 index 0000000000000000000000000000000000000000..daec4e63c2f9ffc1e338c56d62f07b14f13cc299 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/widget/SolarSystemView.java @@ -0,0 +1,311 @@ +package net.oschina.app.improve.widget; + +import android.animation.FloatEvaluator; +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.RadialGradient; +import android.graphics.Shader; +import android.util.AttributeSet; +import android.view.View; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.DecelerateInterpolator; + +import java.util.ArrayList; +import java.util.List; + +/** + * 类太阳系星球转动 + * Created by thanatosx on 16/7/14. + */ +public class SolarSystemView extends View implements Runnable { + + public static final int FLUSH_RATE = 40; + public static final int FLUSH_RATE_LIMITATION = 16; + + private int mFlushRate = FLUSH_RATE; + private int paintCount; + private float pivotX; + private float pivotY; + private Paint mTrackPaint; + private Paint mPlanetPaint; + private Paint mBackgroundPaint; + private List planets; + private Bitmap mCacheBitmap; + + private ValueAnimator mAccelerateAnimator; + private ValueAnimator mDecelerateAnimator; + + public SolarSystemView(Context context) { + this(context, null); + } + + public SolarSystemView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public SolarSystemView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + planets = new ArrayList<>(); + + mTrackPaint = new Paint(); + mTrackPaint.setStyle(Paint.Style.STROKE); + mTrackPaint.setAntiAlias(true); + + mPlanetPaint = new Paint(); + mPlanetPaint.setStyle(Paint.Style.FILL); + mPlanetPaint.setAntiAlias(true); + } + + public void setPivotPoint(float x, float y) { + pivotX = x; + pivotY = y; + paintCount = 0; + prepare(); + } + + public void addPlanets(List planets) { + this.planets.addAll(planets); + } + + public void addPlanets(Planet planet) { + planets.add(planet); + } + + public void clear() { + planets.clear(); + } + + public synchronized void prepare() { + if (planets.size() == 0) return; + + if (mCacheBitmap != null) { + mCacheBitmap.recycle(); + mCacheBitmap = null; + } + mCacheBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(mCacheBitmap); + if (getBackground() != null) { + getBackground().draw(canvas); + } + if (mBackgroundPaint != null && mBackgroundPaint.getShader() != null) { + canvas.drawRect(0, 0, getWidth(), getHeight(), mBackgroundPaint); + } + for (Planet planet : planets) { + mTrackPaint.setStrokeWidth(planet.getTrackWidth()); + mTrackPaint.setColor(planet.getTrackColor()); + canvas.drawCircle(pivotX, pivotY, planet.getRadius(), mTrackPaint); + } + postRepaint(); + } + + /** + * 设置背景渐变 + * 设置中心点之后再做此事 + * + * @param x pivot x + * @param y pivot y + * @param r radius of gradient + * @param sc start color + * @param ec end color + */ + public void setRadialGradient(float x, float y, float r, int sc, int ec) { + mBackgroundPaint = new Paint(); + mBackgroundPaint.setStyle(Paint.Style.FILL); + mBackgroundPaint.setAntiAlias(true); + mBackgroundPaint.setShader(new RadialGradient(x, y, r, sc, ec, Shader.TileMode.CLAMP)); + prepare(); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + prepare(); + } + + @Override + protected void onDraw(Canvas canvas) { + if (planets.size() == 0) return; + + int count = canvas.save(); + if (mCacheBitmap != null) canvas.drawBitmap(mCacheBitmap, 0, 0, mPlanetPaint); + for (Planet planet : planets) { + double y; + double x; + float angle; + if (planet.isClockwise()) { + angle = (planet.getOriginAngle() + paintCount * planet.getAngleRate()) % 360; + } else { + angle = 360 - (planet.getOriginAngle() + paintCount * planet.getAngleRate()) % 360; + } + x = Math.cos(angle) * planet.getRadius() + pivotX; + y = Math.sin(angle) * planet.getRadius() + pivotY; + mPlanetPaint.setColor(planet.getColor()); + canvas.drawCircle((float) x, (float) y, planet.getSelfRadius(), mPlanetPaint); + } + canvas.restoreToCount(count); + ++paintCount; + if (paintCount < 0) paintCount = 0; + } + + private void postRepaint() { + removeCallbacks(this); + postDelayed(this, mFlushRate); + } + + @Override + public void run() { + invalidate(); + postRepaint(); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + prepare(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + if (mCacheBitmap != null) { + mCacheBitmap.recycle(); + mCacheBitmap = null; + } + } + + private ValueAnimator getAccelerateAnimator() { + if (mAccelerateAnimator != null) return mAccelerateAnimator; + mAccelerateAnimator = ValueAnimator.ofFloat(mFlushRate, FLUSH_RATE_LIMITATION); + mAccelerateAnimator.setEvaluator(new FloatEvaluator()); + mAccelerateAnimator.setInterpolator(new DecelerateInterpolator()); + mAccelerateAnimator.setDuration(1000); + mAccelerateAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + mFlushRate = ((Float) animation.getAnimatedValue()).intValue(); + } + }); + return mAccelerateAnimator; + } + + private ValueAnimator getDecelerateAnimator() { + if (mDecelerateAnimator != null) return mDecelerateAnimator; + mDecelerateAnimator = ValueAnimator.ofFloat(mFlushRate, FLUSH_RATE); + mDecelerateAnimator.setEvaluator(new FloatEvaluator()); + mDecelerateAnimator.setInterpolator(new AccelerateInterpolator()); + mDecelerateAnimator.setDuration(1000); + mDecelerateAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + mFlushRate = ((Float) animation.getAnimatedValue()).intValue(); + } + }); + return mDecelerateAnimator; + } + + // 都是在主线程内操作,所以不会有生产者消费者问题 + + public void accelerate() { + if (mFlushRate == FLUSH_RATE_LIMITATION) return; + mFlushRate = FLUSH_RATE; // reset flush rate + ValueAnimator animator = getAccelerateAnimator(); + if (animator.isRunning()) animator.cancel(); + animator.setFloatValues(mFlushRate, FLUSH_RATE_LIMITATION); + animator.start(); + } + + public void decelerate() { + if (mAccelerateAnimator != null && mAccelerateAnimator.isRunning()) { + mAccelerateAnimator.cancel(); + } + if (mFlushRate == FLUSH_RATE) return; + ValueAnimator animator = getDecelerateAnimator(); + if (animator.isRunning()) animator.cancel(); + long duration = (long) (((float) FLUSH_RATE - mFlushRate) / FLUSH_RATE * 1000); + if (duration == 0) { + mFlushRate = FLUSH_RATE; + return; + } + animator.setDuration(duration); + animator.setFloatValues(mFlushRate, FLUSH_RATE); + animator.start(); + } + + public static class Planet { + private int mRadius = 100; + private int mSelfRadius = 6; + private int mTrackWidth = 1; + private int mColor = 0XFF6FDB94; + private int mTrackColor = 0XFF6FDB94; + private float mAngleRate = 0.01F; + private int mOriginAngle = 0; + private boolean isClockwise = true; + + public int getRadius() { + return mRadius; + } + + public void setRadius(int mRadius) { + this.mRadius = mRadius; + } + + public int getSelfRadius() { + return mSelfRadius; + } + + public void setSelfRadius(int mSelfRadius) { + this.mSelfRadius = mSelfRadius; + } + + public int getTrackWidth() { + return mTrackWidth; + } + + public void setTrackWidth(int mTrackWidth) { + this.mTrackWidth = mTrackWidth; + } + + public int getColor() { + return mColor; + } + + public void setColor(int mColor) { + this.mColor = mColor; + } + + public int getTrackColor() { + return mTrackColor; + } + + public void setTrackColor(int mTrackColor) { + this.mTrackColor = mTrackColor; + } + + public float getAngleRate() { + return mAngleRate; + } + + public void setAngleRate(float mAngleRate) { + this.mAngleRate = mAngleRate; + } + + public boolean isClockwise() { + return isClockwise; + } + + public void setClockwise(boolean clockwise) { + isClockwise = clockwise; + } + + public int getOriginAngle() { + return mOriginAngle; + } + + public void setOriginAngle(int mOriginAngle) { + this.mOriginAngle = mOriginAngle; + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/widget/TabPickerView.java b/app/src/main/java/net/oschina/app/improve/widget/TabPickerView.java new file mode 100644 index 0000000000000000000000000000000000000000..8b54d4662da633c7ebfd5d35f4d7717798c2fe3a --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/widget/TabPickerView.java @@ -0,0 +1,747 @@ +package net.oschina.app.improve.widget; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.content.Context; +import android.content.res.ColorStateList; +import android.support.v4.view.MotionEventCompat; +import android.support.v4.widget.NestedScrollView; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.helper.ItemTouchHelper; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewPropertyAnimator; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import net.oschina.app.AppContext; +import net.oschina.app.BuildConfig; +import net.oschina.app.R; +import net.oschina.app.improve.bean.SubTab; +import net.oschina.app.util.TDevice; +import net.oschina.app.util.TLog; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * 动态栏目View 请通过{@link #setTabPickerManager(TabPickerDataManager)}来设置活动数据和原始数据,数据 + * 对象根据需要实现{@link Object#hashCode()}和{@link Object#equals(Object)}方法,因为非活动数据是通过使用 + * {@link List#contains(Object)}方法从原始数据剔除活动数据实现的。 + *

    + *

    活动动态栏目的添加、删除、移动、选择通过{@link OnTabPickingListener}来实现的,你可以通过方法 + * {@link #setOnTabPickingListener(OnTabPickingListener)}来监听。 + *

    + *

    通过{@link #show(int)}和{@link #hide()}方法来显示隐藏动态栏目界面。 + *

    + *

    通过{@link #onTurnBack()}响应回退事件。 + *

    + *

    Created by thanatosx on 16/10/27. + */ +@SuppressWarnings("all") +public class TabPickerView extends FrameLayout { + + private TextView mViewDone; + private TextView mViewOperator; + private RecyclerView mRecyclerActive; + private RecyclerView mRecyclerInactive; + private LinearLayout mLayoutWrapper; + private RelativeLayout mLayoutTop; + private LinearLayout mViewWrapper; + private NestedScrollView mViewScroller; + private ItemTouchHelper mItemTouchHelper; + + private TabAdapter mActiveAdapter; + private TabAdapter mInactiveAdapter; + + private TabPickerDataManager mTabManager; + private OnTabPickingListener mTabPickingListener; + + private Action1 mOnShowAnimator; + private Action1 mOnHideAnimator; + + private int mSelectedIndex = 0; + + public TabPickerView(Context context) { + this(context, null); + } + + public TabPickerView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public TabPickerView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initWidgets(); + } + + /** + * The Tab Picking Listener Interface + */ + public interface OnTabPickingListener { + /** + * 单击选择某个tab + * + * @param position select a tab + */ + void onSelected(int position); + + /** + * 删除某个tab + * + * @param position the moved tab's position + * @param tab the moved tab + */ + void onRemove(int position, SubTab tab); + + /** + * 添加某个tab + * + * @param tab the inserted tab + */ + void onInsert(SubTab tab); + + /** + * 交换tab + * + * @param op the mover's position + * @param mover the moving tab + * @param np the swapper's position + * @param swapper the swapped tab + */ + void onMove(int op, int np); + + /** + * 重新持久化活动的tabs + * + * @param activeTabs the actived tabs + */ + void onRestore(List activeTabs); + } + + public interface Action1 { + void call(T t); + } + + private void initWidgets() { + View view = LayoutInflater.from(getContext()) + .inflate(R.layout.view_tab_picker, this, false); + + mRecyclerActive = (RecyclerView) view.findViewById(R.id.view_recycler_active); + mRecyclerInactive = (RecyclerView) view.findViewById(R.id.view_recycler_inactive); + mViewScroller = (NestedScrollView) view.findViewById(R.id.view_scroller); + mLayoutTop = (RelativeLayout) view.findViewById(R.id.layout_top); + mViewWrapper = (LinearLayout) view.findViewById(R.id.view_wrapper); + mViewDone = (TextView) view.findViewById(R.id.tv_done); + mViewOperator = (TextView) view.findViewById(R.id.tv_operator); + mLayoutWrapper = (LinearLayout) view.findViewById(R.id.layout_wrapper); + mViewDone.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (mViewDone.getText().toString().equals("排序删除")) { + mActiveAdapter.startEditMode(); + } else { + mActiveAdapter.cancelEditMode(); + } + } + }); + + addView(view); + } + + public void setOnShowAnimation(Action1 l) { + this.mOnShowAnimator = l; + } + + public void setOnHideAnimator(Action1 l) { + this.mOnHideAnimator = l; + } + + public void show(int selectedIndex) { + final int tempIndex = mSelectedIndex; + mSelectedIndex = selectedIndex; + mActiveAdapter.notifyItemChanged(tempIndex); + mActiveAdapter.notifyItemChanged(mSelectedIndex); + + if (mOnShowAnimator != null) mOnShowAnimator.call(null); + setVisibility(VISIBLE); + mLayoutTop.setAlpha(0); + mLayoutTop.animate().alpha(1).setDuration(380).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + mLayoutTop.setAlpha(1); + } + }); + + mViewScroller.setTranslationY(-mViewScroller.getHeight()); + mViewScroller.animate().translationY(0).setDuration(380).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + mViewScroller.setTranslationY(0); + } + }); + } + + public void hide() { + if (mTabPickingListener != null) { + mTabPickingListener.onRestore(mTabManager.mActiveDataSet); + mTabPickingListener.onSelected(mSelectedIndex); + } + + if (mOnHideAnimator != null) mOnHideAnimator.call(null); + mLayoutTop.animate().alpha(0).setDuration(380).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + setVisibility(GONE); + } + }); + mViewScroller.animate().translationY(-mViewScroller.getHeight()).setDuration(380); + } + + private void initRecyclerView() { + if (mRecyclerActive.getAdapter() != null && mRecyclerInactive.getAdapter() != null) return; + + /* - set up Active Recycler - */ + mActiveAdapter = new TabAdapter(mTabManager.mActiveDataSet) { + @Override + public TabAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return new TabAdapter.ViewHolder(LayoutInflater.from( + parent.getContext()).inflate(R.layout.view_tab_item, parent, false)); + } + + @Override + public void onBindViewHolder(TabAdapter.ViewHolder holder, int position) { + SubTab item = items.get(position); + holder.mViewTab.setText(item.getName()); + if (item.isFixed()) { + holder.mViewTab.setActivated(false); + } else { + holder.mViewTab.setActivated(true); + } + if (mSelectedIndex == position) { + holder.mViewTab.setSelected(true); + } else { + holder.mViewTab.setSelected(false); + } + if (!TextUtils.isEmpty(item.getTag())) { + holder.mViewBubble.setText(item.getTag()); + holder.mViewBubble.setVisibility(VISIBLE); + } else { + holder.mViewBubble.setVisibility(GONE); + } + if (isEditMode() && !item.isFixed()) { + holder.mViewDel.setVisibility(VISIBLE); + } else { + holder.mViewDel.setVisibility(GONE); + } + if (mBindViewObserver != null) { + mBindViewObserver.call(holder); + } + } + + @Override + public int getItemCount() { + return items.size(); + } + + }; + + mActiveAdapter.setOnClickItemListener(new Action1() { + @Override + public void call(Integer position) { + // 先调用隐藏, 因为隐藏有保存,更新tab的动作 + int tempIndex = mSelectedIndex; + mSelectedIndex = position; + mActiveAdapter.notifyItemChanged(tempIndex); + mActiveAdapter.notifyItemChanged(mSelectedIndex); + hide(); + } + }); + + mActiveAdapter.setOnDeleteItemListener(new Action1() { + @Override + public void call(Integer position) { + SubTab tab = mActiveAdapter.getItem(position); + if (tab == null || tab.isFixed()) return; + int oldCount = mActiveAdapter.getItemCount(); + tab = mActiveAdapter.removeItem(position); + // 放到下面需要根据Original DataSet重排序 + for (SubTab item : mTabManager.mOriginalDataSet) { + if (!item.getToken().equals(tab.getToken())) continue; + tab.setOrder(item.getOrder()); + break; + } + + int i = 0; + for (; i < mTabManager.mInactiveDataSet.size(); i++) { + SubTab item = mTabManager.mInactiveDataSet.get(i); + if (item.getOrder() < tab.getOrder()) continue; + break; + } + mTabManager.mInactiveDataSet.add(i, tab); + mInactiveAdapter.notifyItemInserted(i); + + if (mSelectedIndex == position) { + mSelectedIndex = position == oldCount - 1 ? mSelectedIndex - 1 : mSelectedIndex; + mActiveAdapter.notifyItemChanged(mSelectedIndex); + } else if (mSelectedIndex > position) { + --mSelectedIndex; + mActiveAdapter.notifyItemChanged(mSelectedIndex); + } + if (mTabPickingListener != null) { + mTabPickingListener.onRemove(position, tab); +// mTabPickingListener.onSelected(mSelectedIndex); + } + } + }); + mRecyclerActive.setAdapter(mActiveAdapter); + + mItemTouchHelper = new ItemTouchHelper(mActiveAdapter.newItemTouchHelperCallback()); + mItemTouchHelper.attachToRecyclerView(mRecyclerActive); + mRecyclerActive.setLayoutManager(new GridLayoutManager(getContext(), 4)); + + /* - set up Inactive Recycler - */ + mRecyclerInactive.setLayoutManager(new GridLayoutManager(getContext(), 4)); + mInactiveAdapter = new TabAdapter(mTabManager.mInactiveDataSet) { + @Override + public TabAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return new TabAdapter.ViewHolder(LayoutInflater.from( + parent.getContext()).inflate(R.layout.view_tab_item, parent, false)); + } + + @Override + public void onBindViewHolder(TabAdapter.ViewHolder holder, int position) { + holder.mViewTab.setText(items.get(position).getName()); + } + + @Override + public int getItemCount() { + return items.size(); + } + }; + mInactiveAdapter.setOnClickItemListener(new Action1() { + @Override + public void call(Integer position) { + // fix double click会out of array + if (position < 0 || position >= mInactiveAdapter.getItemCount()) return; + SubTab tab = mInactiveAdapter.removeItem(position); + mActiveAdapter.addItem(tab); + if (mTabPickingListener != null) { + mTabPickingListener.onInsert(tab); + } + } + }); + mRecyclerInactive.setAdapter(mInactiveAdapter); + } + + + public void setTabPickerManager(TabPickerDataManager manager) { + if (manager == null) return; + mTabManager = manager; + initRecyclerView(); + } + + public TabPickerDataManager getTabPickerManager() { + return mTabManager; + } + + public void setOnTabPickingListener(OnTabPickingListener l) { + mTabPickingListener = l; + } + + public boolean onTurnBack() { + if (mActiveAdapter.isEditMode()) { + mActiveAdapter.cancelEditMode(); + return true; + } + if (getVisibility() == VISIBLE) { + hide(); + return true; + } + return false; + } + + /** + * Class TabAdapter + * + * @param + */ + private abstract class TabAdapter + extends RecyclerView.Adapter { + + private View.OnClickListener mClickDeleteListener; + private View.OnClickListener mClickTabItemListener; + private View.OnTouchListener mTouchTabItemListener; + + private Action1 mDeleteItemAction; + private Action1 mSelectItemAction; + Action1 mBindViewObserver; + + private boolean isEditMode = false; + List items; + + TabAdapter(List items) { + this.items = items; + } + + SubTab removeItem(int position) { + SubTab b = items.remove(position); + notifyItemRemoved(position); + return b; + } + + void addItem(SubTab bean) { + items.add(bean); + notifyItemInserted(items.size() - 1); + } + + void addItem(SubTab bean, int index) { + items.add(index, bean); + notifyItemInserted(index); + } + + SubTab getItem(int position) { + if (position < 0 || position >= items.size()) return null; + return items.get(position); + } + + void startEditMode() { + mViewOperator.setText("拖动排序"); + mViewDone.setText("完成"); + + mLayoutWrapper.setVisibility(GONE); + int sh = mViewScroller.getMeasuredHeight(); + int rh = mRecyclerActive.getHeight(); + Log.i("oschina", "sh: " + sh + " rh: " + rh); + if (rh < sh) { + LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) mRecyclerActive.getLayoutParams(); + params.height = sh; + mRecyclerActive.setLayoutParams(params); + } + + isEditMode = true; + notifyDataSetChanged(); + } + + void cancelEditMode() { + mViewOperator.setText("切换栏目"); + mViewDone.setText("排序删除"); + + LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) mRecyclerActive.getLayoutParams(); + params.height = params.WRAP_CONTENT; + mRecyclerActive.setLayoutParams(params); + mLayoutWrapper.setVisibility(VISIBLE); + + + isEditMode = false; + notifyDataSetChanged(); + } + + boolean isEditMode() { + return isEditMode; + } + + void registerBindViewObserver(Action1 l) { + this.mBindViewObserver = l; + } + + void unRegisterBindViewObserver() { + this.mBindViewObserver = null; + } + + OnClickListener getClickTabItemListener() { + if (mClickTabItemListener == null) { + mClickTabItemListener = new OnClickListener() { + @Override + public void onClick(View v) { + ViewHolder holder = (ViewHolder) v.getTag(); + if (holder == null) return; + if (mSelectItemAction != null) { + mSelectItemAction.call(holder.getAdapterPosition()); + } + } + }; + } + return mClickTabItemListener; + } + + OnClickListener getDeleteItemListener() { + if (mClickDeleteListener == null) { + mClickDeleteListener = new OnClickListener() { + @Override + public void onClick(View v) { + ViewHolder holder = (ViewHolder) v.getTag(); + if (holder == null) return; + if (mDeleteItemAction != null) { + mDeleteItemAction.call(holder.getAdapterPosition()); + } + } + }; + } + return mClickDeleteListener; + } + + OnTouchListener getTouchTabItemListener() { + if (mTouchTabItemListener == null) { + mTouchTabItemListener = new OnTabTouchListener(); + } + return mTouchTabItemListener; + } + + void setOnClickItemListener(Action1 l) { + this.mSelectItemAction = l; + } + + void setOnDeleteItemListener(Action1 l) { + this.mDeleteItemAction = l; + } + + TabItemTouchHelperCallback newItemTouchHelperCallback() { + return new TabItemTouchHelperCallback(); + } + + /** + * Tab View Holder + */ + class ViewHolder extends RecyclerView.ViewHolder { + + TextView mViewTab; + TextView mViewBubble; + ImageView mViewDel; + + ViewHolder(View view) { + super(view); + mViewTab = (TextView) view.findViewById(R.id.tv_content); + mViewBubble = (TextView) view.findViewById(R.id.tv_bubble); + mViewDel = (ImageView) view.findViewById(R.id.iv_delete); + + mViewTab.setTextColor(new ColorStateList(new int[][]{ + new int[]{-android.R.attr.state_activated}, + new int[]{} + }, new int[]{0XFF24CF5F, 0XFF6A6A6A}) + ); + mViewTab.setActivated(true); + + mViewTab.setTag(this); + mViewDel.setTag(this); + mViewDel.setOnClickListener(getDeleteItemListener()); + mViewTab.setOnClickListener(getClickTabItemListener()); + mViewTab.setOnTouchListener(getTouchTabItemListener()); + } + } + + /** + * Inner Tab Touch Listener + */ + private class OnTabTouchListener implements OnTouchListener { + + @Override + public boolean onTouch(View v, MotionEvent event) { + ViewHolder holder = (ViewHolder) v.getTag(); + if (holder == null) return false; + if (isEditMode() && MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) { + mItemTouchHelper.startDrag(holder); + return true; + } + return false; + } + } + + class TabItemTouchHelperCallback extends ItemTouchHelper.Callback { + + @Override + public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { + int dragFlag = 0; + int position = viewHolder.getAdapterPosition(); + if (position > 0 && position < items.size()) { + if (!items.get(position).isFixed()) { + dragFlag = ItemTouchHelper.UP + | ItemTouchHelper.DOWN + | ItemTouchHelper.LEFT + | ItemTouchHelper.RIGHT; + } + } + return makeMovementFlags(dragFlag, 0); + } + + @Override + public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, + RecyclerView.ViewHolder target) { + int fromTargetIndex = viewHolder.getAdapterPosition(); + int toTargetIndex = target.getAdapterPosition(); + + if (fromTargetIndex == toTargetIndex) return true; + if (items.get(toTargetIndex).isFixed()) return true; + + SubTab tab = items.remove(fromTargetIndex); + items.add(toTargetIndex, tab); + + if (mSelectedIndex == fromTargetIndex) { + mSelectedIndex = toTargetIndex; + } else if (mSelectedIndex == toTargetIndex) { + mSelectedIndex = fromTargetIndex > toTargetIndex ? mSelectedIndex + 1 : mSelectedIndex - 1; + } else if (toTargetIndex <= mSelectedIndex && mSelectedIndex < fromTargetIndex) { + ++mSelectedIndex; + } else if (fromTargetIndex < mSelectedIndex && mSelectedIndex < toTargetIndex) { + --mSelectedIndex; + } + + notifyItemMoved(fromTargetIndex, toTargetIndex); + if (mTabPickingListener != null) { + mTabPickingListener.onMove(fromTargetIndex, toTargetIndex); + } + return true; + } + + @Override + public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { + // pass + } + + @Override + public void onSelectedChanged(final RecyclerView.ViewHolder viewHolder, int actionState) { + super.onSelectedChanged(viewHolder, actionState); + if (viewHolder == null) return; + ((ViewHolder) viewHolder).mViewTab.setSelected(true); + if (isEditMode()) return; + final int position = viewHolder.getAdapterPosition(); + + // onBindViewHolder之后,ViewHolder.itemView.getParent() != RecycleView + // 估计是在onBindViewHolder之后绑定了ViewParent的,延迟500,暂时没什么好办法 + registerBindViewObserver(new Action1() { + @Override + public void call(final ViewHolder viewHolder) { + int index = viewHolder.getAdapterPosition(); + if (index != position) return; + postDelayed(new Runnable() { + @Override + public void run() { + mItemTouchHelper.startDrag(viewHolder); + } + }, 500); + unRegisterBindViewObserver(); + } + }); + startEditMode(); + } + + @Override + public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { + super.clearView(recyclerView, viewHolder); + if (mSelectedIndex == viewHolder.getAdapterPosition()) return; + ((ViewHolder) viewHolder).mViewTab.setSelected(false); + } + } + + } + + /** + * Tab Data Picker Manager, Manager the Tab Data's behavior + * + * @param + */ + public abstract static class TabPickerDataManager { + + public List mActiveDataSet; + public List mInactiveDataSet; + public List mOriginalDataSet; + + public TabPickerDataManager() { + mActiveDataSet = setupActiveDataSet(); + mOriginalDataSet = setupOriginalDataSet(); + mInactiveDataSet = new ArrayList<>(); + + if (mOriginalDataSet == null || mOriginalDataSet.size() == 0) { + throw new RuntimeException("Original Data Set can't be null or empty"); + } + + TLog.i("oschina", "Active Data Set: " + (mActiveDataSet == null ? "true" : "" + mActiveDataSet.size())); + if (mActiveDataSet == null) { + mActiveDataSet = new ArrayList<>(); + for (SubTab item : mOriginalDataSet) { + if (item.isActived() || item.isFixed()) { + mActiveDataSet.add(item); + } + } + restoreActiveDataSet(mActiveDataSet); + } else if (isUpdate()) { + List mActiveList = new ArrayList<>(); + + // 替换老列表项 + for (SubTab item : mActiveDataSet) { + int position = mOriginalDataSet.indexOf(item); + if (position == -1) continue; + mActiveList.add(mOriginalDataSet.get(position)); + } + + // 将未加入的新项加入活动列表 + for (SubTab item : mOriginalDataSet) { + if (item.isActived() && !mActiveList.contains(item)) { + mActiveList.add(item); + } + } + + mActiveDataSet = mActiveList; + mActiveList = null; + restoreActiveDataSet(mActiveDataSet); + } + + Collections.sort(mActiveDataSet, new Comparator() { + @Override + public int compare(SubTab o1, SubTab o2) { + if (o1.isFixed() && !o2.isFixed()) return -1; + if (!o1.isFixed() && o2.isFixed()) return 1; + return 0; +// return o1.getOrder() - o2.getOrder(); + } + }); + + for (SubTab item : mOriginalDataSet) { + if (mActiveDataSet.contains(item)) continue; + mInactiveDataSet.add(item); + } + } + + + public static boolean isUpdate() { + int mVersionCode = TDevice.getVersionCode(); + int mask = AppContext.get("TabsMask", -1); + TLog.i("oschina", "Current Version Code: " + mVersionCode + ", Mask Version Code: " + mask); + if (BuildConfig.DEBUG) return true; + return mVersionCode != mask; + } + + public List getActiveDataSet() { + return mActiveDataSet; + } + + public List getInActiveDataSet() { + return mInactiveDataSet; + } + + public List getOriginalDataSet() { + return mOriginalDataSet; + } + + public abstract List setupActiveDataSet(); + + public abstract List setupOriginalDataSet(); + + public abstract void restoreActiveDataSet(List mActiveDataSet); + } + +} diff --git a/app/src/main/java/net/oschina/app/improve/widget/TitleBar.java b/app/src/main/java/net/oschina/app/improve/widget/TitleBar.java new file mode 100644 index 0000000000000000000000000000000000000000..b80cbb9bd301f355dff26491c785934ea547aefa --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/widget/TitleBar.java @@ -0,0 +1,126 @@ +package net.oschina.app.improve.widget; + +import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.support.annotation.DrawableRes; +import android.support.annotation.RequiresApi; +import android.support.annotation.StringRes; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import net.oschina.app.R; + +/** + * Created by JuQiu + * on 16/9/5. + */ +public class TitleBar extends FrameLayout { + private static int EXT_PADDING_TOP; + private TextView mTitle; + private ImageView mIcon; + + + public TitleBar(Context context) { + super(context); + init(null, 0, 0); + } + + public TitleBar(Context context, AttributeSet attrs) { + super(context, attrs); + init(attrs, 0, 0); + } + + public TitleBar(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(attrs, defStyleAttr, 0); + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + public TitleBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + init(attrs, defStyleAttr, defStyleRes); + } + + + private void init(AttributeSet attrs, int defStyleAttr, int defStyleRes) { + Context context = getContext(); + + LayoutInflater inflater = LayoutInflater.from(context); + inflater.inflate(R.layout.lay_title_bar, this, true); + + mTitle = (TextView) findViewById(R.id.tv_title); + mIcon = (ImageView) findViewById(R.id.iv_icon); + + + if (attrs != null) { + // Load attributes + final TypedArray a = context.obtainStyledAttributes( + attrs, R.styleable.TitleBar, defStyleAttr, defStyleRes); + + String title = a.getString(R.styleable.TitleBar_aTitle); + Drawable drawable = a.getDrawable(R.styleable.TitleBar_aIcon); + a.recycle(); + + mTitle.setText(title); + mIcon.setImageDrawable(drawable); + } else { + mIcon.setVisibility(GONE); + } + + // Set Background + setBackgroundColor(getResources().getColor(R.color.main_green)); + + // Init padding + setPadding(getLeft(), getTop() + getExtPaddingTop(getResources()), getRight(), getBottom()); + } + + public void setTitle(@StringRes int titleRes) { + if (titleRes <= 0) + return; + mTitle.setText(titleRes); + } + + public void setIcon(@DrawableRes int iconRes) { + if (iconRes <= 0) { + mIcon.setVisibility(GONE); + return; + } + mIcon.setImageResource(iconRes); + mIcon.setVisibility(VISIBLE); + } + + public void setIconOnClickListener(OnClickListener listener) { + mIcon.setOnClickListener(listener); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + float d = getResources().getDisplayMetrics().density; + int minH = (int) (d * 36 + getExtPaddingTop(getResources())); + + heightMeasureSpec = MeasureSpec.makeMeasureSpec(minH, MeasureSpec.EXACTLY); + + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + public static int getExtPaddingTop(Resources resources) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && EXT_PADDING_TOP == 0) { + try { + Class clazz = Class.forName("com.android.internal.R$dimen"); + Object object = clazz.newInstance(); + int height = Integer.parseInt(clazz.getField("status_bar_height") + .get(object).toString()); + EXT_PADDING_TOP = resources.getDimensionPixelSize(height); + } catch (Exception e) { + e.printStackTrace(); + } + } + return EXT_PADDING_TOP; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/widget/TweetPicturesLayout.java b/app/src/main/java/net/oschina/app/improve/widget/TweetPicturesLayout.java new file mode 100644 index 0000000000000000000000000000000000000000..b5688c95bafaa8a552d363f1aa55da02a1245d80 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/widget/TweetPicturesLayout.java @@ -0,0 +1,328 @@ +package net.oschina.app.improve.widget; + +import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.os.Build; +import android.support.annotation.RequiresApi; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +import com.bumptech.glide.BitmapRequestBuilder; +import com.bumptech.glide.Glide; +import com.bumptech.glide.RequestManager; + +import net.oschina.app.R; +import net.oschina.app.improve.bean.Tweet; +import net.oschina.app.improve.media.ImageGalleryActivity; +import net.oschina.common.utils.CollectionUtil; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by JuQiu + * on 16/8/26. + */ +public class TweetPicturesLayout extends ViewGroup implements View.OnClickListener { + private static final int SINGLE_MAX_W = 120; + private static final int SINGLE_MAX_H = 180; + private static final int SINGLE_MIN_W = 34; + private static final int SINGLE_MIN_H = 34; + + private Tweet.Image[] mImages; + private float mVerticalSpacing; + private float mHorizontalSpacing; + private int mColumn; + private int mMaxPictureSize; + + public TweetPicturesLayout(Context context) { + this(context, null); + } + + public TweetPicturesLayout(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public TweetPicturesLayout(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(attrs, defStyleAttr, 0); + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + public TweetPicturesLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + init(attrs, defStyleAttr, defStyleRes); + } + + private void init(AttributeSet attrs, int defStyleAttr, int defStyleRes) { + final Context context = getContext(); + final Resources resources = getResources(); + final float density = resources.getDisplayMetrics().density; + + int vSpace = (int) (4 * density); + int hSpace = vSpace; + + if (attrs != null) { + // Load attributes + final TypedArray a = context.obtainStyledAttributes( + attrs, R.styleable.TweetPicturesLayout, defStyleAttr, defStyleRes); + + // Load clip touch corner radius + vSpace = a.getDimensionPixelOffset(R.styleable.TweetPicturesLayout_verticalSpace, vSpace); + hSpace = a.getDimensionPixelOffset(R.styleable.TweetPicturesLayout_horizontalSpace, hSpace); + setColumn(a.getInt(R.styleable.TweetPicturesLayout_column, 3)); + setMaxPictureSize(a.getDimensionPixelOffset(R.styleable.TweetPicturesLayout_maxPictureSize, 0)); + a.recycle(); + } + + setVerticalSpacing(vSpace); + setHorizontalSpacing(hSpace); + } + + public void setHorizontalSpacing(float pixelSize) { + mHorizontalSpacing = pixelSize; + } + + public void setVerticalSpacing(float pixelSize) { + mVerticalSpacing = pixelSize; + } + + public void setColumn(int column) { + if (column < 1) + column = 1; + if (column > 20) + column = 20; + mColumn = column; + } + + public void setMaxPictureSize(int maxPictureSize) { + if (maxPictureSize < 0) + maxPictureSize = 0; + mMaxPictureSize = maxPictureSize; + } + + public void setImage(Tweet.Image[] images) { + if (mImages == images) + return; + + // 移除布局 + removeAllImage(); + + // 过滤掉不合法的数据 + if (images != null) { + List isOkImages = new ArrayList<>(); + for (Tweet.Image image : images) { + if (Tweet.Image.check(image)) + isOkImages.add(image); + } + images = CollectionUtil.toArray(isOkImages, Tweet.Image.class); + } + + // 赋值 + mImages = images; + + if (mImages != null && mImages.length > 0) { + LayoutInflater inflater = LayoutInflater.from(this.getContext()); + RequestManager requestManager = Glide.with(getContext()); + for (int i = 0; i < mImages.length; i++) { + Tweet.Image image = mImages[i]; + if (!Tweet.Image.check(image)) + continue; + + View view = inflater.inflate(R.layout.lay_tweet_image_item, this, false); + view.setTag(i); + view.setOnClickListener(this); + String path = image.getThumb(); + BitmapRequestBuilder builder = requestManager.load(path) + .asBitmap() + .centerCrop() + //.placeholder(R.color.grey_50) + .error(R.mipmap.ic_split_graph); + + if (path.toLowerCase().endsWith("gif")) { + //builder = builder.diskCacheStrategy(DiskCacheStrategy.SOURCE); + view.findViewById(R.id.iv_is_gif).setVisibility(VISIBLE); + } + addView(view); + builder.into((ImageView) view.findViewById(R.id.iv_picture)); + } + + // all do requestLayout + if (getVisibility() == VISIBLE) { + requestLayout(); + } else { + setVisibility(View.VISIBLE); + } + } else { + setVisibility(View.GONE); + } + } + + public void setImage(String[] images) { + if (images == null || images.length == 0) return; + Tweet.Image[] ims = new Tweet.Image[images.length]; + for (int i = 0; i < images.length; i++) { + ims[i] = Tweet.Image.create(images[i]); + } + setImage(ims); + } + + public void removeAllImage() { + removeAllViews(); + mImages = null; + } + + private int getMaxChildSize(int size) { + if (mMaxPictureSize == 0) + return size; + else + return Math.min(mMaxPictureSize, size); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int paddingLeft = getPaddingLeft(); + int paddingTop = getPaddingTop(); + int paddingRight = getPaddingRight(); + int paddingBottom = getPaddingBottom(); + + int selfWidth = resolveSize(paddingLeft + paddingRight, widthMeasureSpec); + int wantedHeight = paddingBottom + paddingTop; + final int childCount = getChildCount(); + + + //noinspection StatementWithEmptyBody + if (childCount == 0) { + // Not have child we can only need padding size + } else if (childCount == 1) { + Tweet.Image image = mImages[0]; + if (Tweet.Image.check(image)) { + int imageW = image.getW(); + int imageH = image.getH(); + imageW = imageW <= 0 ? 100 : imageW; + imageH = imageH <= 0 ? 100 : imageH; + + float density = getResources().getDisplayMetrics().density; + // Get max width and height + float maxContentW = Math.min(selfWidth - paddingRight - paddingLeft, density * SINGLE_MAX_W); + float maxContentH = density * SINGLE_MAX_H; + + int childW, childH; + + float hToW = imageH / (float) imageW; + if (hToW > (maxContentH / maxContentW)) { + childH = (int) maxContentH; + childW = (int) (maxContentH / hToW); + } else { + childW = (int) maxContentW; + childH = (int) (maxContentW * hToW); + } + // Check the width and height below Min values + int minW = (int) (SINGLE_MIN_W * density); + if (childW < minW) + childW = minW; + int minH = (int) (SINGLE_MIN_H * density); + if (childH < minH) + childH = minH; + + View child = getChildAt(0); + if (child != null) { + child.measure(MeasureSpec.makeMeasureSpec(childW, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(childH, MeasureSpec.EXACTLY)); + wantedHeight += childH; + } + } + } else { + // Measure all child + final float maxContentWidth = selfWidth - paddingRight - paddingLeft - mHorizontalSpacing * (mColumn - 1); + // Get child size + final int childSize = getMaxChildSize((int) (maxContentWidth / mColumn)); + + for (int i = 0; i < childCount; ++i) { + View childView = getChildAt(i); + childView.measure(MeasureSpec.makeMeasureSpec(childSize, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(childSize, MeasureSpec.EXACTLY)); + } + + int lines = (int) (childCount / (float) mColumn + 0.9); + wantedHeight += (int) (lines * childSize + mVerticalSpacing * (lines - 1)); + } + + setMeasuredDimension(selfWidth, resolveSize(wantedHeight, heightMeasureSpec)); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + float childCount = getChildCount(); + if (childCount > 0) { + int paddingLeft = getPaddingLeft(); + int paddingTop = getPaddingTop(); + + if (childCount == 1) { + View childView = getChildAt(0); + int childWidth = childView.getMeasuredWidth(); + int childHeight = childView.getMeasuredHeight(); + childView.layout(paddingLeft, paddingTop, paddingLeft + childWidth, paddingTop + childHeight); + } else { + int mWidth = r - l; + int paddingRight = getPaddingRight(); + + int lineHeight = 0; + int childLeft = paddingLeft; + int childTop = paddingTop; + + for (int i = 0; i < childCount; ++i) { + View childView = getChildAt(i); + + if (childView.getVisibility() == View.GONE) { + continue; + } + + int childWidth = childView.getMeasuredWidth(); + int childHeight = childView.getMeasuredHeight(); + + lineHeight = Math.max(childHeight, lineHeight); + + if (childLeft + childWidth + paddingRight > mWidth) { + childLeft = paddingLeft; + childTop += mVerticalSpacing + lineHeight; + lineHeight = childHeight; + } + childView.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight); + childLeft += childWidth + mHorizontalSpacing; + } + } + } + } + + @Override + public void onClick(View v) { + Tweet.Image[] images = mImages; + if (images == null || images.length <= 0) + return; + + Object obj = v.getTag(); + if (obj == null || !(obj instanceof Integer)) + return; + + int index = (int) obj; + if (index < 0) + index = 0; + if (index >= images.length) + index = images.length - 1; + + Tweet.Image image = images[index]; + if (!Tweet.Image.check(image)) + return; + + String[] paths = Tweet.Image.getImagePath(images); + if (paths == null || paths.length <= 0) + return; + + ImageGalleryActivity.show(getContext(), paths, index); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/widget/ViewEventBanner.java b/app/src/main/java/net/oschina/app/improve/widget/ViewEventBanner.java new file mode 100644 index 0000000000000000000000000000000000000000..37fcffa6cd2715a5abdb64d81ba13a7605356fbd --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/widget/ViewEventBanner.java @@ -0,0 +1,68 @@ +package net.oschina.app.improve.widget; + +import android.content.Context; +import android.graphics.Bitmap; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.bumptech.glide.RequestManager; +import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; +import com.bumptech.glide.load.resource.bitmap.BitmapTransformation; + +import net.oschina.app.R; +import net.oschina.app.bean.Banner; +import net.oschina.app.util.UIHelper; +import net.qiujuer.genius.graphics.Blur; + +/** + * Created by huanghaibin + * on 16-5-23. + */ +public class ViewEventBanner extends RelativeLayout implements View.OnClickListener { + private Banner banner; + private ImageView iv_event_banner_img, iv_event_banner_bg; + private TextView tv_event_banner_title, tv_event_banner_body; + + public ViewEventBanner(Context context) { + super(context, null); + init(context); + } + + private void init(Context context) { + LayoutInflater.from(context).inflate(R.layout.view_event_banner, this, true); + iv_event_banner_img = (ImageView) findViewById(R.id.iv_event_banner_img); + iv_event_banner_bg = (ImageView) findViewById(R.id.iv_event_banner_bg); + tv_event_banner_title = (TextView) findViewById(R.id.tv_event_banner_title); + tv_event_banner_body = (TextView) findViewById(R.id.tv_event_banner_body); + setOnClickListener(this); + } + + public void initData(RequestManager manager, Banner banner) { + this.banner = banner; + tv_event_banner_title.setText(banner.getName()); + tv_event_banner_body.setText(banner.getDetail()); + manager.load(banner.getImg()).into(iv_event_banner_img); + manager.load(banner.getImg()).centerCrop() + .transform(new BitmapTransformation(getContext()) { + @Override + protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) { + toTransform = Blur.onStackBlur(toTransform, 25, true); + return toTransform; + } + + @Override + public String getId() { + return "blur"; + } + }) + .into(iv_event_banner_bg); + } + + @Override + public void onClick(View v) { + UIHelper.showBannerDetail(getContext(), banner); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/widget/ViewNewsBanner.java b/app/src/main/java/net/oschina/app/improve/widget/ViewNewsBanner.java new file mode 100644 index 0000000000000000000000000000000000000000..44d80261436aa6312b77a37037668b1012db8251 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/widget/ViewNewsBanner.java @@ -0,0 +1,52 @@ +package net.oschina.app.improve.widget; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ImageView; +import android.widget.RelativeLayout; + +import com.bumptech.glide.RequestManager; + +import net.oschina.app.R; +import net.oschina.app.bean.Banner; +import net.oschina.app.util.UIHelper; + +/** + * Created by huanghaibin + * on 16-5-23. + */ +public class ViewNewsBanner extends RelativeLayout implements View.OnClickListener { + private Banner banner; + private ImageView iv_banner; + + public ViewNewsBanner(Context context) { + super(context, null); + init(context); + } + + private void init(Context context) { + LayoutInflater.from(context).inflate(R.layout.view_news_banner, this, true); + iv_banner = (ImageView) findViewById(R.id.iv_banner); + setOnClickListener(this); + } + + public void initData(RequestManager manager, Banner banner) { + this.banner = banner; + manager.load(banner.getImg()).into(iv_banner); + } + + @Override + public void onClick(View v) { + if (banner != null) { + int type = banner.getType(); + long id = banner.getId(); + UIHelper.showDetail(getContext(), type, id, banner.getHref()); + } + } + + + public String getTitle() { + return banner.getName(); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/widget/banner/BannerView.java b/app/src/main/java/net/oschina/app/improve/widget/banner/BannerView.java new file mode 100644 index 0000000000000000000000000000000000000000..9131c9a917d15afbfde39122649091e0f87f7278 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/widget/banner/BannerView.java @@ -0,0 +1,57 @@ +package net.oschina.app.improve.widget.banner; + +import android.content.Context; +import android.os.Handler; +import android.support.v4.view.ViewPager; +import android.util.AttributeSet; +import android.view.MotionEvent; + +/** + * Created by haibin + * on 2016/11/29. + */ + +public class BannerView extends ViewPager implements Runnable { + private Handler mHandler; + private int mDelay; + + public BannerView(Context context) { + super(context); + } + + public BannerView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + switch (ev.getAction()) { + case MotionEvent.ACTION_DOWN: + break; + case MotionEvent.ACTION_UP: + break; + case MotionEvent.ACTION_MOVE: + break; + } + return super.onTouchEvent(ev); + } + + @Override + public void run() { + + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mHandler = new Handler(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + mHandler.removeCallbacksAndMessages(null); + mHandler = null; + } + +} diff --git a/app/src/main/java/net/oschina/app/improve/widget/banner/EventHeaderView.java b/app/src/main/java/net/oschina/app/improve/widget/banner/EventHeaderView.java new file mode 100644 index 0000000000000000000000000000000000000000..5a7c9e987127f48cc513baaace51c1db0183808c --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/widget/banner/EventHeaderView.java @@ -0,0 +1,45 @@ +package net.oschina.app.improve.widget.banner; + +import android.content.Context; +import android.view.ViewGroup; + +import com.bumptech.glide.RequestManager; + +import net.oschina.app.R; +import net.oschina.app.improve.widget.ViewEventBanner; + +/** + * Created by haibin + * on 2016/10/26. + */ + +public class EventHeaderView extends HeaderView { + public EventHeaderView(Context context, RequestManager loader, String api, String bannerCache) { + super(context, loader, api, bannerCache); + } + + @Override + protected int getLayoutId() { + return R.layout.layout_event_header_view; + } + + @Override + protected Object instantiateItem(ViewGroup container, int position) { + ViewEventBanner view = new ViewEventBanner(getContext()); + if (mBanners.size() != 0) { + int p = position % mBanners.size(); + if (p >= 0 && p < mBanners.size()) { + view.initData(mImageLoader, mBanners.get(p)); + } + } + container.addView(view); + return view; + } + + @Override + protected void destroyItem(ViewGroup container, int position, Object object) { + if (object instanceof ViewEventBanner) { + container.removeView((ViewEventBanner) object); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/widget/banner/HeaderView.java b/app/src/main/java/net/oschina/app/improve/widget/banner/HeaderView.java new file mode 100644 index 0000000000000000000000000000000000000000..fbfc173316a8bf2370e64283d28cb03d624d1fed --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/widget/banner/HeaderView.java @@ -0,0 +1,214 @@ +package net.oschina.app.improve.widget.banner; + +import android.content.Context; +import android.os.Handler; +import android.support.v4.view.PagerAdapter; +import android.support.v4.view.ViewPager; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.RelativeLayout; + +import com.bumptech.glide.RequestManager; +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; + +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.bean.Banner; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.bean.base.PageBean; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.utils.CacheManager; +import net.oschina.app.improve.widget.indicator.CirclePagerIndicator; + +import java.util.ArrayList; +import java.util.List; + +import cz.msebera.android.httpclient.Header; + +/** + * Created by haibin + * on 2016/10/26. + */ + +public abstract class HeaderView extends RelativeLayout implements ViewPager.OnPageChangeListener, Runnable { + protected ViewPager mViewPager; + protected CirclePagerIndicator mIndicator; + protected List mBanners; + protected BannerAdapter mAdapter; + protected Handler mHandler; + protected int mCurrentItem; + protected RequestManager mImageLoader; + protected TextHttpResponseHandler mCallBack; + protected String mUrl; + private boolean isScrolling; + protected String mBannerCache; + + public HeaderView(Context context, RequestManager loader, String api, String bannerCache) { + super(context); + mImageLoader = loader; + this.mUrl = api; + this.mBannerCache = bannerCache; + init(context); + } + + protected void init(Context context) { + //mHandler = new Handler(); + mBanners = new ArrayList<>(); + List banners = CacheManager.readListJson(context, mBannerCache, Banner.class); + if (banners != null) { + mBanners.addAll(banners); + if (mHandler == null) + mHandler = new Handler(); + mHandler.postDelayed(this, 5000); + } + LayoutInflater.from(context).inflate(getLayoutId(), this, true); + mViewPager = (ViewPager) findViewById(R.id.vp_banner); + mIndicator = (CirclePagerIndicator) findViewById(R.id.indicator); + mAdapter = new BannerAdapter(); + mViewPager.addOnPageChangeListener(this); + mViewPager.setAdapter(mAdapter); + mIndicator.bindViewPager(mViewPager); + mIndicator.setCount(mBanners.size()); + + new SmoothScroller(getContext()).bingViewPager(mViewPager); + mViewPager.setOnTouchListener(new OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + isScrolling = true; + case MotionEvent.ACTION_UP: + isScrolling = false; + break; + case MotionEvent.ACTION_CANCEL: + isScrolling = false; + break; + case MotionEvent.ACTION_MOVE: + isScrolling = true; + break; + } + return false; + } + }); + mCallBack = new TextHttpResponseHandler() { + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + try { + ResultBean> result = AppOperator.createGson().fromJson(responseString, + new TypeToken>>() { + }.getType()); + if (result != null && result.isSuccess()) { + CacheManager.saveToJson(getContext(), mBannerCache, result.getResult().getItems()); + setBanners(result.getResult().getItems()); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + }; + requestBanner(); + } + + @Override + public void run() { + mHandler.postDelayed(this, 5000); + if (isScrolling) + return; + mCurrentItem = mCurrentItem + 1; + mViewPager.setCurrentItem(mCurrentItem); + } + + public void requestBanner() { + if (mHandler == null) + mHandler = new Handler(); + mHandler.removeCallbacks(this); + OSChinaApi.getBanner(mUrl, mCallBack); + } + + void setBanners(List banners) { + if (banners != null) { + mHandler.removeCallbacks(this); + mBanners.clear(); + mBanners.addAll(banners); + mViewPager.getAdapter().notifyDataSetChanged(); + mIndicator.setCount(mBanners.size()); + mIndicator.notifyDataSetChanged(); + if (mCurrentItem == 0 && mBanners.size() != 1) { + mCurrentItem = mBanners.size() * 1000; + mViewPager.setCurrentItem(mCurrentItem); + } + if (mBanners.size() > 1) { + mHandler.postDelayed(this, 5000); + } + } + } + + protected abstract int getLayoutId(); + + protected abstract Object instantiateItem(ViewGroup container, int position); + + protected abstract void destroyItem(ViewGroup container, int position, Object object); + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + isScrolling = mCurrentItem != position; + } + + @Override + public void onPageSelected(int position) { + isScrolling = false; + mCurrentItem = position; + } + + @Override + public void onPageScrollStateChanged(int state) { + isScrolling = state != ViewPager.SCROLL_STATE_IDLE; + } + + private class BannerAdapter extends PagerAdapter { + @Override + public int getCount() { + return mBanners.size() == 1 ? 1 : Integer.MAX_VALUE; + } + + @Override + public boolean isViewFromObject(View view, Object object) { + return view == object; + } + + @Override + public Object instantiateItem(ViewGroup container, int position) { + return HeaderView.this.instantiateItem(container, position); + } + + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + HeaderView.this.destroyItem(container, position, object); + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + if (mHandler == null) + mHandler = new Handler(); + mHandler.postDelayed(this, 5000); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + if (mHandler == null) + return; + mHandler.removeCallbacks(this); + mHandler = null; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/widget/banner/NewsHeaderView.java b/app/src/main/java/net/oschina/app/improve/widget/banner/NewsHeaderView.java new file mode 100644 index 0000000000000000000000000000000000000000..f54f13ce9788ea2b7f0834d5a2b300c736cad9a2 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/widget/banner/NewsHeaderView.java @@ -0,0 +1,73 @@ +package net.oschina.app.improve.widget.banner; + +import android.content.Context; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.bumptech.glide.RequestManager; + +import net.oschina.app.R; +import net.oschina.app.bean.Banner; +import net.oschina.app.improve.widget.ViewNewsBanner; + +import java.util.List; + +/** + * Created by haibin + * on 2016/10/26. + */ + +public class NewsHeaderView extends HeaderView { + private TextView mTitleTextView; + + public NewsHeaderView(Context context, RequestManager loader, String api, String bannerCache) { + super(context, loader, api, bannerCache); + } + + @Override + protected void init(Context context) { + super.init(context); + mTitleTextView = (TextView) findViewById(R.id.tv_title); + } + + @Override + protected int getLayoutId() { + return R.layout.layout_news_header_view; + } + + @Override + public void onPageSelected(int position) { + super.onPageSelected(position); + if (mBanners.size() != 0) + mTitleTextView.setText(mBanners.get(position % mBanners.size()).getName()); + } + + @Override + void setBanners(List banners) { + super.setBanners(banners); + if (banners.size() > 0 && mCurrentItem == 0) { + mTitleTextView.setText(banners.get(0).getName()); + } + } + + @Override + protected Object instantiateItem(ViewGroup container, int position) { + ViewNewsBanner view = new ViewNewsBanner(getContext()); + if (mBanners.size() != 0) { + int p = position % mBanners.size(); + if (p >= 0 && p < mBanners.size()) { + view.initData(mImageLoader, mBanners.get(p)); + + } + } + container.addView(view); + return view; + } + + @Override + protected void destroyItem(ViewGroup container, int position, Object object) { + if (object instanceof ViewNewsBanner) { + container.removeView((ViewNewsBanner) object); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/widget/banner/SmoothScroller.java b/app/src/main/java/net/oschina/app/improve/widget/banner/SmoothScroller.java new file mode 100644 index 0000000000000000000000000000000000000000..402b475810d9d02793c672118162cafc901c7116 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/widget/banner/SmoothScroller.java @@ -0,0 +1,49 @@ +package net.oschina.app.improve.widget.banner; + +import android.content.Context; +import android.support.v4.view.ViewPager; +import android.view.animation.Interpolator; +import android.widget.Scroller; + +import java.lang.reflect.Field; + +/** + * Created by huanghaibin + * on 16-5-26. + */ +public class SmoothScroller extends Scroller { + private int mDuration = 1200; // + + public SmoothScroller(Context context) { + super(context); + } + + public SmoothScroller(Context context, Interpolator interpolator) { + super(context, interpolator); + } + + @Override + public void startScroll(int startX, int startY, int dx, int dy, int duration) { + super.startScroll(startX, startY, dx, dy, mDuration); + } + + @Override + public void startScroll(int startX, int startY, int dx, int dy) { + super.startScroll(startX, startY, dx, dy, mDuration); + } + + public void bingViewPager(ViewPager viewPager) { + try { + Field mScroller = null; + mScroller = ViewPager.class.getDeclaredField("mScroller"); + mScroller.setAccessible(true); + mScroller.set(viewPager, this); + } catch (NoSuchFieldException e) { + e.printStackTrace(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } +} diff --git a/app/src/main/java/net/oschina/app/improve/widget/banner/ZoomTransformer.java b/app/src/main/java/net/oschina/app/improve/widget/banner/ZoomTransformer.java new file mode 100644 index 0000000000000000000000000000000000000000..39180c058e272fec49517dac0634ccb20953f1e0 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/widget/banner/ZoomTransformer.java @@ -0,0 +1,41 @@ +package net.oschina.app.improve.widget.banner; + +import android.support.v4.view.ViewPager.PageTransformer; +import android.view.View; + +/** + * Created by haibin + * on 2016/11/26. + */ +public class ZoomTransformer implements PageTransformer { + private static final float MIN_SCALE = 0.85f; + + private static final float MIN_ALPHA = 0.5f; + + @Override + public void transformPage(View view, float position) { + int pageWidth = view.getWidth(); + int pageHeight = view.getHeight(); + + if (position < -1) { + view.setAlpha(0); + view.setTranslationX(0); + } else if (position <= 1) { + float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position)); + float vertMargin = pageHeight * (1 - scaleFactor) / 2; + float horzMargin = pageWidth * (1 - scaleFactor) / 2; + if (position < 0) { + view.setTranslationX(horzMargin - vertMargin / 2); + } else { + view.setTranslationX(-horzMargin + vertMargin / 2); + } + view.setScaleX(scaleFactor); + view.setScaleY(scaleFactor); + view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) + / (1 - MIN_SCALE) * (1 - MIN_ALPHA)); + } else { + view.setAlpha(0); + view.setTranslationX(0); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/oschina/app/improve/widget/indicator/BannerIndicator.java b/app/src/main/java/net/oschina/app/improve/widget/indicator/BannerIndicator.java new file mode 100644 index 0000000000000000000000000000000000000000..23c0d4590819361793c568e841c1395bdf9a95a7 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/widget/indicator/BannerIndicator.java @@ -0,0 +1,16 @@ +package net.oschina.app.improve.widget.indicator; + +/** + * Created by haibin + * on 2016/11/24. + */ + +public interface BannerIndicator extends BannerView.OnViewChangeListener { + void bindBannerView(BannerView view); + + void setCurrentItem(int currentItem); + + void setOnViewChangeListener(BannerView.OnViewChangeListener listener); + + void notifyDataSetChange(); +} diff --git a/app/src/main/java/net/oschina/app/improve/widget/indicator/BannerView.java b/app/src/main/java/net/oschina/app/improve/widget/indicator/BannerView.java new file mode 100644 index 0000000000000000000000000000000000000000..9562b56cf6a0e2f2d9cc4b395a3f2c366693f051 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/widget/indicator/BannerView.java @@ -0,0 +1,388 @@ +package net.oschina.app.improve.widget.indicator; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.content.Context; +import android.database.DataSetObservable; +import android.database.DataSetObserver; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.VelocityTracker; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.DecelerateInterpolator; +import android.widget.FrameLayout; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by haibin + * on 2016/11/18. + */ +@SuppressWarnings("all") +public class BannerView extends FrameLayout implements View.OnClickListener { + + private PointInfo mStart; + private PointInfo mEnd; + private ViewAdapter mAdapter; + private int mCurrentPosition; + + private float mOffset; + private float mAlpha; + private float mNextAlpha; + private boolean isUpdate; + private boolean isClick; + + private VelocityTracker mTracker; + private PagerObserver mObserver; + + private OnItemClickListener mOnItemClickListener; + private List mViewChangeListeners; + + public BannerView(Context context) { + super(context); + mStart = new PointInfo(); + mEnd = new PointInfo(); + } + + public BannerView(Context context, AttributeSet attrs) { + super(context, attrs); + mStart = new PointInfo(); + mEnd = new PointInfo(); + setOnClickListener(this); + } + + public void setCurrentItem(int position) { + int count = mAdapter.getCount(); + if (position <= count - 1 && count >= 2) { + this.mCurrentPosition = position == 0 ? mCurrentPosition = count - 1 : position - 1; + selected(count); + } + } + + @Override + public void onClick(View v) { + if (mOnItemClickListener != null && isClick) { + mOnItemClickListener.onItemClick(mCurrentPosition); + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (mAdapter == null) return super.onTouchEvent(event); + int count = mAdapter.getCount(); + if (count <= 1) return super.onTouchEvent(event); + + int with = getWidth(); + int height = getHeight(); + + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + mStart.setX(event.getX()); + mStart.setY(event.getY()); + mTracker = VelocityTracker.obtain(); + requestDisallowInterceptTouchEvent(true); + break; + case MotionEvent.ACTION_MOVE: + mOffset = mStart.getX() - event.getX(); + mAlpha = (with - Math.abs(mOffset)) / with; + mTracker.addMovement(event); + mTracker.computeCurrentVelocity(1000); + if (event.getY() >= height) { + isClick = true; + return false; + } + if ((Math.abs(mOffset)) > 50) { + isClick = false; + notifyViewStateChanged(OnViewChangeListener.STATE_DRAGGING); + actionMove(count); + } + break; + case MotionEvent.ACTION_UP://结束时候 + isClick = (Math.abs(mOffset)) < 50; + actionUp(count); + notifyViewStateChanged(OnViewChangeListener.STATE_IDLE); + break; + } + return super.onTouchEvent(event); + } + + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + return true; + } + + private void actionMove(int count) { + View curView = getChildAt(1); + View preView = getChildAt(0); + View nextView = getChildAt(2); + curView.setAlpha(mAlpha); + if (count == 2) { + preView.setAlpha(1); + notifyViewScrolled(mCurrentPosition == 1 ? 0 : 1); + } else { + if (mOffset > 0) {//向左滑+1 + int width = getWidth(); + preView.setAlpha(0); + mNextAlpha = (Math.abs(mOffset)) / width; + nextView.setAlpha(mNextAlpha); + notifyViewScrolled(mCurrentPosition + 1); + } else { + preView.setAlpha(1); + nextView.setAlpha(0); + notifyViewScrolled(mCurrentPosition - 1); + } + } + } + + private void actionUp(int count) { + View curView = getChildAt(1); + View preView = getChildAt(0); + View nextView = getChildAt(2); + + if (mAlpha < 0.7 && mAlpha != 0.0f && !isUpdate) {//触发切换 + isUpdate = true; + int index = 0; + if (count == 2) { + removeView(preView); + addView(preView); + mCurrentPosition = (mCurrentPosition + 1) % count; + } else { + if (mOffset <= 0) {//右滑-1 + removeView(nextView); + if (mCurrentPosition == 0) { + mCurrentPosition = count - 1; + index = mCurrentPosition - 1; + } else { + --mCurrentPosition; + index = mCurrentPosition == 0 ? count - 1 : mCurrentPosition - 1; + } + View view = mAdapter.instantiateItem(this, index); + removeView(view); + addView(view, 0); + } else {//左滑+1 + mCurrentPosition = (mCurrentPosition + 1) % count; + this.removeView(preView); + preView.setAlpha(0); + //nextView.setAlpha(1); + showAlphaAnimation(nextView, mNextAlpha); + index = (mCurrentPosition + 1) % count; + mAdapter.instantiateItem(this, index); + getChildAt(2).setAlpha(0); + curView.setAlpha(1); + } + } + //curView.setAlpha(0); + hideAlphaAnimation(curView, mAlpha); + notifySelected(); + } else { + //curView.setAlpha(1); + //避免点击闪烁 + if (mAlpha == 1.0f || mAlpha == 0.0f) + return; + showAlphaAnimation(curView, mAlpha); + if (count >= 3) { + preView.setAlpha(1); + nextView.setAlpha(0); + } + } + isUpdate = false; + } + + private void selected(int count) { + isUpdate = true; + View curView = getChildAt(1); + View preView = getChildAt(0); + View nextView = getChildAt(2); + int index = 0; + if (count == 2) { + removeView(preView); + addView(preView); + } else { + mCurrentPosition = (mCurrentPosition + 1) % count; + this.removeView(preView); + preView.setAlpha(0); + showAlphaAnimation(nextView, 0.3f); + index = (mCurrentPosition + 1) % count; + mAdapter.instantiateItem(this, index); + getChildAt(2).setAlpha(0); + notifySelected(); + } + //curView.setAlpha(0); + //hideAlphaAnimation(curView,0.5f); + notifyViewStateChanged(OnViewChangeListener.STATE_IDLE); + mOffset = 0.0f; + mAlpha = 0.0f; + isUpdate = false; + } + + private void notifySelected() { + if (mViewChangeListeners != null) { + for (OnViewChangeListener listener : mViewChangeListeners) { + listener.onViewSelected(mCurrentPosition); + } + } + } + + private void notifyViewStateChanged(int state) { + if (mViewChangeListeners != null) { + for (OnViewChangeListener listener : mViewChangeListeners) { + listener.onViewStateChanged(state); + } + } + } + + private void notifyViewScrolled(int p) { + if (mViewChangeListeners != null) { + for (OnViewChangeListener listener : mViewChangeListeners) { + listener.onViewScrolled(p, mOffset); + } + } + } + + public void addOnViewChangeListener(OnViewChangeListener listener) { + if (mViewChangeListeners == null) mViewChangeListeners = new ArrayList<>(); + mViewChangeListeners.add(listener); + } + + public void setOnItemClickListener(OnItemClickListener listener) { + this.mOnItemClickListener = listener; + } + + + public void setAdapter(ViewAdapter adapter) { + if (mAdapter != null) { + mAdapter.setViewPagerObserver(null); + } + final ViewAdapter oldAdapter = mAdapter; + mAdapter = adapter; + + int count = mAdapter.getCount(); + + if (count == 0) + return; + + if (count >= 1) { + mAdapter.instantiateItem(this, count - 1); + } + if (count >= 2) { + mAdapter.instantiateItem(this, 0); + } + if (count >= 3) { + mAdapter.instantiateItem(this, 1); + getChildAt(2).setAlpha(0); + } + } + + void dataSetChanged() { + + } + + private void hideAlphaAnimation(final View view, float curAlpha) { + view.clearAnimation(); + view.setAlpha(curAlpha); + + view.animate().alpha(0.f).setDuration(800).setInterpolator(new DecelerateInterpolator()).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + view.setAlpha(0.f); + } + }); + } + + private void showAlphaAnimation(final View view, float curAlpha) { + view.clearAnimation(); + view.setAlpha(curAlpha); + view.animate().alpha(1.f).setDuration(800).setInterpolator(new DecelerateInterpolator()).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + view.setAlpha(1.f); + } + }); + + } + + private static class PointInfo { + private float x; + private float y; + + public float getX() { + return x; + } + + public void setX(float x) { + this.x = x; + } + + public float getY() { + return y; + } + + public void setY(float y) { + this.y = y; + } + } + + public abstract static class ViewAdapter { + private final DataSetObservable mObservable = new DataSetObservable(); + private DataSetObserver mViewPagerObserver; + + public abstract View instantiateItem(ViewGroup parent, int position); + + public abstract int getCount(); + + public void destroyItem(ViewGroup parent, View view) { + parent.removeView(view); + } + + void setViewPagerObserver(DataSetObserver observer) { + synchronized (this) { + mViewPagerObserver = observer; + } + } + + public void notifyDataSetChange() { + synchronized (this) { + if (mViewPagerObserver != null) { + mViewPagerObserver.onChanged(); + } + } + mObservable.notifyChanged(); + } + } + + public ViewAdapter getAdapter() { + return mAdapter; + } + + public interface OnViewChangeListener { + static final int STATE_IDLE = -1; + static final int STATE_DRAGGING = 1; + + void onViewScrolled(int position, float positionOffset); + + void onViewSelected(int position); + + void onViewStateChanged(int state); + } + + private class PagerObserver extends DataSetObserver { + @Override + public void onChanged() { + dataSetChanged(); + } + + @Override + public void onInvalidated() { + dataSetChanged(); + } + } + + public interface OnItemClickListener { + void onItemClick(int position); + } +} diff --git a/app/src/main/java/net/oschina/app/improve/widget/indicator/CircleBannerIndicator.java b/app/src/main/java/net/oschina/app/improve/widget/indicator/CircleBannerIndicator.java new file mode 100644 index 0000000000000000000000000000000000000000..7cb5fa306a1fe7f8395b7af3c3a487bae608b402 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/widget/indicator/CircleBannerIndicator.java @@ -0,0 +1,206 @@ +package net.oschina.app.improve.widget.indicator; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.util.AttributeSet; +import android.view.View; + +import net.oschina.app.R; + + +/** + * Created by haibin + * on 2016/11/24. + */ +@SuppressWarnings("unused") +public class CircleBannerIndicator extends View implements BannerIndicator { + private float mRadius; + private float mIndicatorRadius; + private final Paint mPaintFill = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint mPaintStroke = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint mPaintIndicator = new Paint(Paint.ANTI_ALIAS_FLAG); + + private int mCurrentPage; + private float mPageOffset; + private boolean mCenterHorizontal; + + private float mIndicatorSpace; + + private BannerView.OnViewChangeListener mOnViewChangeListener; + private BannerView mBannerView; + + public CircleBannerIndicator(Context context, AttributeSet attrs) { + super(context, attrs); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleBannerIndicator); + + mCenterHorizontal = a.getBoolean(R.styleable.CircleBannerIndicator_circle_banner_indicator_centerHorizontal, true); + mPaintFill.setStyle(Paint.Style.FILL); + mPaintFill.setColor(a.getColor(R.styleable.CircleBannerIndicator_circle_banner_indicator_color, 0x0000ff)); + mPaintStroke.setStyle(Paint.Style.STROKE); + mPaintStroke.setColor(a.getColor(R.styleable.CircleBannerIndicator_circle_banner_indicator_stroke_color, 0x000000)); + mPaintStroke.setStrokeWidth(a.getDimension(R.styleable.CircleBannerIndicator_circle_banner_indicator_stroke_width, 0)); + mPaintIndicator.setStyle(Paint.Style.FILL); + mPaintIndicator.setColor(a.getColor(R.styleable.CircleBannerIndicator_circle_banner_indicator_fill_color, 0x0000ff)); + mRadius = a.getDimension(R.styleable.CircleBannerIndicator_circle_banner_indicator_radius, 10); + mIndicatorSpace = a.getDimension(R.styleable.CircleBannerIndicator_circle_banner_indicator_space, 20); + mIndicatorRadius = a.getDimension(R.styleable.CircleBannerIndicator_circle_banner_indicator_indicator_radius, 10); + if (mIndicatorRadius < mRadius) mIndicatorRadius = mRadius; + a.recycle(); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + if (mBannerView == null) { + return; + } + final int count = mBannerView.getAdapter().getCount(); + + if (count <= 1) { + return; + } + + if (mCurrentPage >= count) { + setCurrentItem(count - 1); + return; + } + + int width = getWidth(); + int paddingLeft = getPaddingLeft(); + int paddingRight = getPaddingRight(); + int paddingTop = getPaddingTop(); + + final float circleAndSpace = 2 * mRadius + mIndicatorSpace;//直径+圆的间隔 + final float yOffset = getHeight() / 2;//竖直方向圆心偏移量,剧中对齐 + float xOffset = paddingLeft + mRadius;//水平方向圆心偏移量 + + //如果采用水平居中对齐 + if (mCenterHorizontal) { + xOffset = (width - count * 2 * mRadius - (count - 1) * mIndicatorSpace) / 2 - mRadius; + } + + float cX; + float cY; + + float strokeRadius = mRadius; + //如果绘制外圆 + if (mPaintStroke.getStrokeWidth() > 0) { + strokeRadius -= mPaintStroke.getStrokeWidth() / 2.0f; + } + + //绘制所有圆点 + for (int i = 0; i < count; i++) { + + cX = xOffset + (i * circleAndSpace);//计算下个圆绘制起点偏移量 + cY = yOffset; + + //绘制圆 + if (mPaintFill.getAlpha() > 0) { + canvas.drawCircle(cX, cY, strokeRadius, mPaintFill); + } + + //绘制外圆 + if (strokeRadius != mRadius) { + canvas.drawCircle(cX, cY, mRadius, mPaintStroke); + } + } + + float cx = mCurrentPage * circleAndSpace; + + cX = xOffset + cx; + cY = yOffset; + canvas.drawCircle(cX, cY, mIndicatorRadius, mPaintIndicator); + } + + @Override + public void bindBannerView(BannerView view) { + if (view == null) + return; + if (view.getAdapter() == null) { + throw new IllegalStateException("BannerView does not set adapter"); + } + this.mBannerView = view; + this.mBannerView.addOnViewChangeListener(this); + invalidate(); + } + + @Override + public void setCurrentItem(int currentItem) { + if (mBannerView == null) { + throw new IllegalStateException("indicator has not bind BannerView"); + } + mBannerView.setCurrentItem(currentItem); + mCurrentPage = currentItem; + invalidate(); + } + + @Override + public void setOnViewChangeListener(BannerView.OnViewChangeListener listener) { + + } + + @Override + public void notifyDataSetChange() { + invalidate(); + requestLayout(); + } + + @Override + public void onViewScrolled(int position, float positionOffset) { + + } + + @Override + public void onViewSelected(int position) { + mCurrentPage = position; + invalidate(); + } + + @Override + public void onViewStateChanged(int state) { + + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec)); + } + + private int measureWidth(int measureSpec) { + int width; + int specMode = MeasureSpec.getMode(measureSpec); + int specSize = MeasureSpec.getSize(measureSpec); + + if ((specMode == MeasureSpec.EXACTLY) || (mBannerView == null)) { + width = specSize; + } else { + final int count = mBannerView.getAdapter().getCount(); + width = (int) (getPaddingLeft() + getPaddingRight() + + (count * 2 * mRadius) + (mIndicatorRadius - mRadius) * 2 + (count - 1) * mIndicatorSpace); + if (specMode == MeasureSpec.AT_MOST) { + width = Math.min(width, specSize); + } + } + return width; + } + + private int measureHeight(int measureSpec) { + int height; + int specMode = MeasureSpec.getMode(measureSpec); + int specSize = MeasureSpec.getSize(measureSpec); + + if (specMode == MeasureSpec.EXACTLY) { + height = specSize; + } else { + height = (int) (2 * mRadius + getPaddingTop() + getPaddingBottom() + 1); + if (specMode == MeasureSpec.AT_MOST) { + height = Math.min(height, specSize); + } + } + return height; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/widget/indicator/CirclePagerIndicator.java b/app/src/main/java/net/oschina/app/improve/widget/indicator/CirclePagerIndicator.java new file mode 100644 index 0000000000000000000000000000000000000000..8190a7be6f2ef62443a73ede104deab4e5b67d5c --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/widget/indicator/CirclePagerIndicator.java @@ -0,0 +1,245 @@ +package net.oschina.app.improve.widget.indicator; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.support.v4.view.ViewPager; +import android.util.AttributeSet; +import android.view.View; + +import net.oschina.app.R; + + +/** + * Created by huanghaibin + * on 16-5-19. + */ +@SuppressWarnings("unused") +public class CirclePagerIndicator extends View implements PagerIndicator { + private float mRadius; + private float mIndicatorRadius; + private final Paint mPaintFill = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint mPaintStroke = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint mPaintIndicator = new Paint(Paint.ANTI_ALIAS_FLAG); + private ViewPager mViewPager; + private ViewPager.OnPageChangeListener mListener; + private int mCurrentPage; + private int mFollowPage; + private float mPageOffset; + private boolean mCenterHorizontal; + private boolean mIsFollow; + private float mIndicatorSpace; + + private int mCount; + + public CirclePagerIndicator(Context context) { + this(context, null); + } + + public CirclePagerIndicator(Context context, AttributeSet attrs) { + super(context, attrs); + + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CirclePagerIndicator); + + mCenterHorizontal = a.getBoolean(R.styleable.CirclePagerIndicator_circle_indicator_centerHorizontal, true); + mPaintFill.setStyle(Paint.Style.FILL); + mPaintFill.setColor(a.getColor(R.styleable.CirclePagerIndicator_circle_indicator_color, 0x0000ff)); + mPaintStroke.setStyle(Paint.Style.STROKE); + mPaintStroke.setColor(a.getColor(R.styleable.CirclePagerIndicator_circle_indicator_stroke_color, 0x000000)); + mPaintStroke.setStrokeWidth(a.getDimension(R.styleable.CirclePagerIndicator_circle_indicator_stroke_width, 0)); + mPaintIndicator.setStyle(Paint.Style.FILL); + mPaintIndicator.setColor(a.getColor(R.styleable.CirclePagerIndicator_circle_indicator_fill_color, 0x0000ff)); + mRadius = a.getDimension(R.styleable.CirclePagerIndicator_circle_indicator_radius, 10); + mIndicatorSpace = a.getDimension(R.styleable.CirclePagerIndicator_circle_indicator_space, 20); + mIndicatorRadius = a.getDimension(R.styleable.CirclePagerIndicator_circle_indicator_indicator_radius, 10); + mIsFollow = a.getBoolean(R.styleable.CirclePagerIndicator_circle_indicator_follow, false); + if (mIndicatorRadius < mRadius) mIndicatorRadius = mRadius; + a.recycle(); + } + + @Override + protected void onDraw(Canvas canvas) { + + super.onDraw(canvas); + + if (mViewPager == null) { + return; + } + final int count = mCount; + if (count == 0) { + return; + } + + if (mCurrentPage >= count) { + setCurrentItem(count - 1); + return; + } + + int width = getWidth(); + int paddingLeft = getPaddingLeft(); + int paddingRight = getPaddingRight(); + int paddingTop = getPaddingTop(); + + final float circleAndSpace = 2 * mRadius + mIndicatorSpace;//直径+圆的间隔 + final float yOffset = getHeight() / 2;//竖直方向圆心偏移量,剧中对齐 + float xOffset = paddingLeft + mRadius;//水平方向圆心偏移量 + + //如果采用水平居中对齐 + if (mCenterHorizontal) { + //xOffset += ((width - paddingLeft - paddingRight) - (count * circleAndSpace)) / 2.0f; + xOffset = (width - count * 2 * mRadius - (count - 1) * mIndicatorSpace) / 2 - mRadius; + } + + float cX; + float cY; + + float strokeRadius = mRadius; + //如果绘制外圆 + if (mPaintStroke.getStrokeWidth() > 0) { + strokeRadius -= mPaintStroke.getStrokeWidth() / 2.0f; + } + + //绘制所有圆点 + for (int i = 0; i < count; i++) { + + cX = xOffset + (i * circleAndSpace);//计算下个圆绘制起点偏移量 + cY = yOffset; + + //绘制圆 + if (mPaintFill.getAlpha() > 0) { + canvas.drawCircle(cX, cY, strokeRadius, mPaintFill); + } + + //绘制外圆 + if (strokeRadius != mRadius) { + canvas.drawCircle(cX, cY, mRadius, mPaintStroke); + } + } + + float cx = (!mIsFollow ? mFollowPage : mCurrentPage) * circleAndSpace; + + //指示器选择缓慢移动 + if (mIsFollow) { + cx += mPageOffset * circleAndSpace; + } + + cX = xOffset + cx; + cY = yOffset; + canvas.drawCircle(cX, cY, mIndicatorRadius, mPaintIndicator); + } + + public void setCount(int count) { + this.mCount = count; + } + + @Override + public void bindViewPager(ViewPager view) { + if (mViewPager == view) { + return; + } + if (view.getAdapter() == null) { + throw new IllegalStateException("ViewPager does not set adapter"); + } + mViewPager = view; + mViewPager.addOnPageChangeListener(this); + invalidate(); + } + + @Override + public void bindViewPager(ViewPager view, int initialPosition) { + bindViewPager(view); + setCurrentItem(initialPosition); + } + + @Override + public void setCurrentItem(int item) { + if (mViewPager == null) { + throw new IllegalStateException("indicator has not bind ViewPager"); + } + mViewPager.setCurrentItem(item); + mCurrentPage = item; + invalidate(); + } + + @Override + public void notifyDataSetChanged() { + invalidate(); + requestLayout(); + } + + @Override + public void onPageScrollStateChanged(int state) { + if (mListener != null) { + mListener.onPageScrollStateChanged(state); + } + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + mCurrentPage = mCount == 0 ? mCount : position % mCount; + mPageOffset = positionOffset; + //如果指示器跟随ViewPager缓慢滑动,那么滚动的时候都绘制界面 + if (mIsFollow) { + invalidate(); + } + if (mListener != null) { + mListener.onPageScrolled(position, positionOffset, positionOffsetPixels); + } + } + + @Override + public void onPageSelected(int position) { + mCurrentPage = mCount == 0 ? mCount : position % mCount; + mFollowPage = mCount == 0 ? mCount : position % mCount; + invalidate(); + if (mListener != null) { + mListener.onPageSelected(position); + } + } + + @Override + public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) { + mListener = listener; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec)); + } + + private int measureWidth(int measureSpec) { + int width; + int specMode = MeasureSpec.getMode(measureSpec); + int specSize = MeasureSpec.getSize(measureSpec); + + if ((specMode == MeasureSpec.EXACTLY) || (mViewPager == null)) { + width = specSize; + } else { + final int count = mCount; + width = (int) (getPaddingLeft() + getPaddingRight() + + (count * 2 * mRadius) + (mIndicatorRadius - mRadius) * 2 + (count - 1) * mIndicatorSpace); + if (specMode == MeasureSpec.AT_MOST) { + width = Math.min(width, specSize); + } + } + return width; + } + + private int measureHeight(int measureSpec) { + int height; + int specMode = MeasureSpec.getMode(measureSpec); + int specSize = MeasureSpec.getSize(measureSpec); + + if (specMode == MeasureSpec.EXACTLY) { + height = specSize; + } else { + height = (int) (2 * mRadius + getPaddingTop() + getPaddingBottom() + 1); + if (specMode == MeasureSpec.AT_MOST) { + height = Math.min(height, specSize); + } + } + return height; + } +} diff --git a/app/src/main/java/net/oschina/app/improve/widget/indicator/LinePagerIndicator.java b/app/src/main/java/net/oschina/app/improve/widget/indicator/LinePagerIndicator.java new file mode 100644 index 0000000000000000000000000000000000000000..7b3c5f518bf38345382c9788f06d06ef06c64545 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/widget/indicator/LinePagerIndicator.java @@ -0,0 +1,226 @@ +package net.oschina.app.improve.widget.indicator; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.support.v4.view.ViewPager; +import android.util.AttributeSet; +import android.view.View; + +import net.oschina.app.R; + + +/** + * Created by huanghaibin + * on 16-5-19. + */ +@SuppressWarnings("unused") +public class LinePagerIndicator extends View implements PagerIndicator { + + //绘制Line的画笔 + private final Paint mPaintFull = new Paint(Paint.ANTI_ALIAS_FLAG); + + //绘制Line指示器当前位置的画笔 + private final Paint mPaintIndicator = new Paint(Paint.ANTI_ALIAS_FLAG); + + private ViewPager mViewPager; + private ViewPager.OnPageChangeListener mListener; + private float mPageOffset; + private int mCurrentPage; + private int mFollowPage; + private boolean mCenterHorizontal; + private float mLineWidth; + private float mLineHeight; + private float mLineIndicatorHeight; + private float mSpace; + private boolean mIsFollow; + + + public LinePagerIndicator(Context context) { + this(context, null); + } + + @SuppressWarnings("SuspiciousNameCombination") + public LinePagerIndicator(Context context, AttributeSet attrs) { + super(context, attrs); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LinePagerIndicator); + mCenterHorizontal = a.getBoolean(R.styleable.LinePagerIndicator_line_indicator_centerHorizontal, true); + mLineWidth = a.getDimension(R.styleable.LinePagerIndicator_line_indicator_width, 10); + mSpace = a.getDimension(R.styleable.LinePagerIndicator_line_indicator_space, 5); + mLineHeight = a.getDimension(R.styleable.LinePagerIndicator_line_indicator_height, 0); + mLineIndicatorHeight = a.getDimension(R.styleable.LinePagerIndicator_line_indicator_indicator_height, mLineHeight); + mPaintFull.setColor(a.getColor(R.styleable.LinePagerIndicator_line_indicator_fill_color, 0x000000)); + mPaintIndicator.setColor(a.getColor(R.styleable.LinePagerIndicator_line_indicator_indicator_color, 0x00ff00)); + mIsFollow = a.getBoolean(R.styleable.LinePagerIndicator_line_indicator_follow, true); + a.recycle(); + + mPaintIndicator.setStrokeWidth(mLineIndicatorHeight > mLineHeight ? mLineIndicatorHeight : mLineHeight); + mPaintFull.setStrokeWidth(mLineHeight); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + if (mViewPager == null) { + return; + } + + final int count = mViewPager.getAdapter().getCount(); + if (count == 0) { + return; + } + + if (mCurrentPage >= count) { + setCurrentItem(count - 1); + return; + } + + final float lineWidthAndSpace = mLineWidth + mSpace;//线宽和间距 + final float indicatorWidth = (count * lineWidthAndSpace) - mSpace;//指示器+间隔 + + final float paddingTop = getPaddingTop(); + final float paddingLeft = getPaddingLeft(); + final float paddingRight = getPaddingRight(); + + float verticalOffset = paddingTop + ((getHeight() - paddingTop - getPaddingBottom()) / 2.0f);//绘制线的中心竖直方向偏移量 + float horizontalOffset = paddingLeft;////绘制线的中心水平方向偏移量 + + //如果采用水平居中对齐的水平偏移量 + if (mCenterHorizontal) { + horizontalOffset += ((getWidth() - paddingLeft - paddingRight) - indicatorWidth) / 2.0f; + } + + float startX; + float stopX; + + for (int i = 0; i < count; i++) { + startX = horizontalOffset + (i * lineWidthAndSpace);////计算下个圆绘制起点偏移量 + stopX = startX + mLineWidth; + canvas.drawLine(startX, verticalOffset, stopX, verticalOffset, mPaintFull); + } + + + float currentSpace = (!mIsFollow ? mFollowPage : mCurrentPage) * lineWidthAndSpace; + + + //指示器选择缓慢移动 + if (mIsFollow) { + currentSpace += mPageOffset * lineWidthAndSpace; + } + + startX = horizontalOffset + currentSpace; + stopX = startX + mLineWidth; + canvas.drawLine(startX, verticalOffset, stopX, verticalOffset, mPaintIndicator); + } + + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec)); + } + + + private int measureWidth(int measureSpec) { + float width; + int specMode = MeasureSpec.getMode(measureSpec); + int specSize = MeasureSpec.getSize(measureSpec); + + if ((specMode == MeasureSpec.EXACTLY) || (mViewPager == null)) { + width = specSize; + } else { + final int count = mViewPager.getAdapter().getCount(); + width = getPaddingLeft() + getPaddingRight() + (count * mLineWidth) + ((count - 1) * mSpace); + if (specMode == MeasureSpec.AT_MOST) { + width = Math.min(width, specSize); + } + } + return (int) Math.ceil(width); + } + + private int measureHeight(int measureSpec) { + float height; + int specMode = MeasureSpec.getMode(measureSpec); + int specSize = MeasureSpec.getSize(measureSpec); + if (specMode == MeasureSpec.EXACTLY) { + height = specSize; + } else { + height = mPaintIndicator.getStrokeWidth() + getPaddingTop() + getPaddingBottom(); + if (specMode == MeasureSpec.AT_MOST) { + height = Math.min(height, specSize); + } + } + return (int) Math.ceil(height); + } + + @Override + public void bindViewPager(ViewPager viewPager) { + if (mViewPager == viewPager) { + return; + } + if (viewPager.getAdapter() == null) { + throw new IllegalStateException("ViewPager does not set adapter"); + } + mViewPager = viewPager; + mViewPager.addOnPageChangeListener(this); + invalidate(); + } + + @Override + public void bindViewPager(ViewPager view, int initialPosition) { + bindViewPager(view); + setCurrentItem(initialPosition); + } + + @Override + public void setCurrentItem(int item) { + if (mViewPager == null) { + throw new IllegalStateException("indicator has not bind ViewPager"); + } + mViewPager.setCurrentItem(item); + mCurrentPage = item; + invalidate(); + } + + @Override + public void notifyDataSetChanged() { + invalidate(); + } + + @Override + public void onPageScrollStateChanged(int state) { + if (mListener != null) { + mListener.onPageScrollStateChanged(state); + } + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + mCurrentPage = position; + mPageOffset = positionOffset; + //如果指示器跟随ViewPager缓慢滑动,那么滚动是时候都绘制界面 + if (mIsFollow) { + invalidate(); + } + if (mListener != null) { + mListener.onPageScrolled(position, positionOffset, positionOffsetPixels); + } + } + + @Override + public void onPageSelected(int position) { + mCurrentPage = position; + mFollowPage = position; + invalidate(); + if (mListener != null) { + mListener.onPageSelected(position); + } + } + + @Override + public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) { + mListener = listener; + } +} \ No newline at end of file diff --git a/app/src/main/java/net/oschina/app/improve/widget/indicator/PagerIndicator.java b/app/src/main/java/net/oschina/app/improve/widget/indicator/PagerIndicator.java new file mode 100644 index 0000000000000000000000000000000000000000..bbdfe52ff73b8e2fa68d50b8c3a9da7696b5005b --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/widget/indicator/PagerIndicator.java @@ -0,0 +1,48 @@ +package net.oschina.app.improve.widget.indicator; + +import android.support.v4.view.ViewPager; + +/** + * Created by huanghaibin + * on 16-5-19. + * 抽象指示器 + */ +@SuppressWarnings("unused") +public interface PagerIndicator extends ViewPager.OnPageChangeListener { + + /** + * bind the viewPager into indicator + * + * @param viewPager the ViewPager + */ + void bindViewPager(ViewPager viewPager); + + + /** + * bind the viewPager into indicator + * + * @param viewPager the ViewPager + * @param initialPosition initialPosition + */ + void bindViewPager(ViewPager viewPager, int initialPosition); + + + /** + * the ViewPager Current Item + * + * @param currentItem currentItem + */ + void setCurrentItem(int currentItem); + + /** + * the ViewPager ChangeListener + * + * @param listener listener + */ + void setOnPageChangeListener(ViewPager.OnPageChangeListener listener); + + /** + * update the DataSet,invalidate + */ + void notifyDataSetChanged(); +} diff --git a/app/src/main/java/net/oschina/app/improve/widget/indicator/TrianglePagerIndicator.java b/app/src/main/java/net/oschina/app/improve/widget/indicator/TrianglePagerIndicator.java new file mode 100644 index 0000000000000000000000000000000000000000..32bc094e353c9c381b93bc87b8a69c2ae5724f69 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/widget/indicator/TrianglePagerIndicator.java @@ -0,0 +1,81 @@ +package net.oschina.app.improve.widget.indicator; + +import android.content.Context; +import android.graphics.Paint; +import android.graphics.Path; +import android.support.v4.view.ViewPager; +import android.util.AttributeSet; +import android.widget.LinearLayout; + +import java.util.List; + +/** + * Created by huanghaibin + * on 16-6-15. + */ +public class TrianglePagerIndicator extends LinearLayout implements PagerIndicator { + + private static final int MAX_TRIANGLE_WIDTH = 130; + private static final int MAX_TRIANGLE_HEIGHT = 50; + + private static final int TEXT_COLOR_NORMAL = 0xFFF6F6F6; + private static final int TEXT_COLOR_SELECT = 0x00000000; + private static final int INDICATOR_COLOR_NORMAL = 0xFFF6F6F6; + private static final int INDICATOR_COLOR_SELECT = 0x00000000; + + private Paint mPaint = new Paint(); + private Path mPath = new Path(); + + private int mTriangleWidth; + private int mTriangleHeight; + + private List tabTitles; + + public TrianglePagerIndicator(Context context) { + super(context); + } + + public TrianglePagerIndicator(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + public void bindViewPager(ViewPager viewPager) { + + } + + @Override + public void bindViewPager(ViewPager viewPager, int initialPosition) { + + } + + @Override + public void setCurrentItem(int currentItem) { + + } + + @Override + public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) { + + } + + @Override + public void notifyDataSetChanged() { + + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + + } + + @Override + public void onPageSelected(int position) { + + } + + @Override + public void onPageScrollStateChanged(int state) { + + } +} diff --git a/app/src/main/java/net/oschina/app/improve/widget/listenerAdapter/TextWatcherAdapter.java b/app/src/main/java/net/oschina/app/improve/widget/listenerAdapter/TextWatcherAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..b714fc8e525c490c613efc52142571a7451ee00f --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/widget/listenerAdapter/TextWatcherAdapter.java @@ -0,0 +1,25 @@ +package net.oschina.app.improve.widget.listenerAdapter; + +import android.text.Editable; +import android.text.TextWatcher; + +/** + * @author qiujuer Email:qiujuer@live.cn + * @version 1.0.0 + */ +public class TextWatcherAdapter implements TextWatcher { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + + } +} diff --git a/app/src/main/java/net/oschina/app/improve/widget/togglebutton/ToggleButton.java b/app/src/main/java/net/oschina/app/improve/widget/togglebutton/ToggleButton.java new file mode 100644 index 0000000000000000000000000000000000000000..15edcd5beacc94528ab00064932acf7505d91bc5 --- /dev/null +++ b/app/src/main/java/net/oschina/app/improve/widget/togglebutton/ToggleButton.java @@ -0,0 +1,334 @@ +package net.oschina.app.improve.widget.togglebutton; + +import android.animation.ObjectAnimator; +import android.animation.TypeEvaluator; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Paint.Cap; +import android.graphics.Paint.Style; +import android.graphics.RectF; +import android.os.Build; +import android.util.AttributeSet; +import android.util.Property; +import android.view.View; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.Interpolator; + +import net.oschina.app.R; + +/** + * @author Qiujuer + */ +public class ToggleButton extends View { + /** */ + private float radius; + /** + * 开启颜色 + */ + private int onColor = Color.parseColor("#4ebb7f"); + /** + * 关闭颜色 + */ + private int offBorderColor = Color.parseColor("#dadbda"); + /** + * 灰色带颜色 + */ + private int offColor = Color.parseColor("#ffffff"); + /** + * 手柄颜色 + */ + private int spotColor = Color.parseColor("#ffffff"); + /** + * 边框颜色 + */ + private int borderColor = offBorderColor; + /** + * 画笔 + */ + private Paint paint; + /** + * 开关状态 + */ + private boolean toggleOn = false; + /** + * 边框大小 + */ + private int borderWidth = 2; + /** + * 垂直中心 + */ + private float centerY; + /** + * 按钮的开始和结束位置 + */ + private float startX, endX; + /** + * 手柄X位置的最小和最大值 + */ + private float spotMinX, spotMaxX; + /** + * 手柄大小 + */ + private int spotSize; + /** + * 手柄X位置 + */ + private float spotX; + /** + * 关闭时内部灰色带高度 + */ + private float offLineWidth; + /** */ + private RectF rect = new RectF(); + + private OnToggleChanged listener; + + private ToggleButton(Context context) { + super(context); + } + + public ToggleButton(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + setup(attrs); + } + + public ToggleButton(Context context, AttributeSet attrs) { + super(context, attrs); + setup(attrs); + } + + public void setup(AttributeSet attrs) { + paint = new Paint(Paint.ANTI_ALIAS_FLAG); + paint.setStyle(Style.FILL); + paint.setStrokeCap(Cap.ROUND); + + this.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View arg0) { + toggle(); + } + }); + + TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.ToggleButton); + offBorderColor = typedArray.getColor(R.styleable.ToggleButton_offBorderColor, offBorderColor); + onColor = typedArray.getColor(R.styleable.ToggleButton_onColor, onColor); + spotColor = typedArray.getColor(R.styleable.ToggleButton_spotColor, spotColor); + offColor = typedArray.getColor(R.styleable.ToggleButton_offColor, offColor); + borderWidth = typedArray.getDimensionPixelSize(R.styleable.ToggleButton_toggle_border_width, borderWidth); + typedArray.recycle(); + } + + public void toggle() { + toggleOn = !toggleOn; + animateCheckedState(toggleOn); + if (listener != null) { + listener.onToggle(toggleOn); + } + } + + public void toggleOn() { + setToggleOn(); + if (listener != null) { + listener.onToggle(toggleOn); + } + } + + public void toggleOff() { + setToggleOff(); + if (listener != null) { + listener.onToggle(toggleOn); + } + } + + /** + * 设置显示成打开样式,不会触发toggle事件 + */ + public void setToggleOn() { + toggleOn = true; + setAnimatorProperty(true); + } + + /** + * 设置显示成关闭样式,不会触发toggle事件 + */ + public void setToggleOff() { + toggleOn = false; + setAnimatorProperty(false); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, + int bottom) { + super.onLayout(changed, left, top, right, bottom); + + final int width = getWidth(); + final int height = getHeight(); + radius = Math.min(width, height) * 0.5f; + centerY = radius; + startX = radius; + endX = width - radius; + spotMinX = startX + borderWidth; + spotMaxX = endX - borderWidth; + spotSize = height - 4 * borderWidth; + + // update values + setAnimatorProperty(toggleOn); + } + + @Override + public void draw(Canvas canvas) { + rect.set(0, 0, getWidth(), getHeight()); + paint.setColor(borderColor); + canvas.drawRoundRect(rect, radius, radius, paint); + + if (offLineWidth > 0) { + final float cy = offLineWidth * 0.5f; + rect.set(spotX - cy, centerY - cy, endX + cy, centerY + cy); + paint.setColor(offColor); + canvas.drawRoundRect(rect, cy, cy, paint); + } + + rect.set(spotX - 1 - radius, centerY - radius, spotX + 1.1f + radius, centerY + radius); + paint.setColor(borderColor); + canvas.drawRoundRect(rect, radius, radius, paint); + + final float spotR = spotSize * 0.5f; + rect.set(spotX - spotR, centerY - spotR, spotX + spotR, centerY + spotR); + paint.setColor(spotColor); + canvas.drawRoundRect(rect, spotR, spotR, paint); + } + + /** + * ============================================================================================= + * The Animate + * ============================================================================================= + */ + private static final Interpolator ANIMATION_INTERPOLATOR = new DecelerateInterpolator(); + private static final int ANIMATION_DURATION = 280; + private ObjectAnimator mAnimator; + + private void animateCheckedState(boolean newCheckedState) { + AnimatorProperty property = new AnimatorProperty(); + if (newCheckedState) { + property.color = onColor; + property.offLineWidth = 10; + property.spotX = spotMaxX; + } else { + property.color = offBorderColor; + property.offLineWidth = spotSize; + property.spotX = spotMinX; + } + + if (mAnimator == null) { + mAnimator = ObjectAnimator.ofObject(this, ANIM_VALUE, new AnimatorEvaluator(mCurProperty), property); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) + mAnimator.setAutoCancel(true); + mAnimator.setDuration(ANIMATION_DURATION); + mAnimator.setInterpolator(ANIMATION_INTERPOLATOR); + } else { + mAnimator.cancel(); + mAnimator.setObjectValues(property); + } + mAnimator.start(); + } + + /** + * ============================================================================================= + * The custom properties + * ============================================================================================= + */ + + private AnimatorProperty mCurProperty = new AnimatorProperty(); + + private void setAnimatorProperty(AnimatorProperty property) { + this.spotX = property.spotX; + this.borderColor = property.color; + this.offLineWidth = property.offLineWidth; + invalidate(); + } + + private void setAnimatorProperty(boolean isOn) { + AnimatorProperty property = mCurProperty; + if (isOn) { + property.color = onColor; + property.offLineWidth = 10; + property.spotX = spotMaxX; + } else { + property.color = offBorderColor; + property.offLineWidth = spotSize; + property.spotX = spotMinX; + } + setAnimatorProperty(property); + } + + private final static class AnimatorProperty { + private int color; + private float offLineWidth; + private float spotX; + } + + private final static class AnimatorEvaluator implements TypeEvaluator { + private final AnimatorProperty mProperty; + + public AnimatorEvaluator(AnimatorProperty property) { + mProperty = property; + } + + @Override + public AnimatorProperty evaluate(float fraction, AnimatorProperty startValue, AnimatorProperty endValue) { + // Values + mProperty.spotX = (int) (startValue.spotX + (endValue.spotX - startValue.spotX) * fraction); + + mProperty.offLineWidth = (int) (startValue.offLineWidth + (endValue.offLineWidth - startValue.offLineWidth) * (1 - fraction)); + + // Color + int startA = (startValue.color >> 24) & 0xff; + int startR = (startValue.color >> 16) & 0xff; + int startG = (startValue.color >> 8) & 0xff; + int startB = startValue.color & 0xff; + + int endA = (endValue.color >> 24) & 0xff; + int endR = (endValue.color >> 16) & 0xff; + int endG = (endValue.color >> 8) & 0xff; + int endB = endValue.color & 0xff; + + mProperty.color = (startA + (int) (fraction * (endA - startA))) << 24 | + (startR + (int) (fraction * (endR - startR))) << 16 | + (startG + (int) (fraction * (endG - startG))) << 8 | + (startB + (int) (fraction * (endB - startB))); + + return mProperty; + } + } + + private final static Property ANIM_VALUE = new Property(AnimatorProperty.class, "animValue") { + @Override + public AnimatorProperty get(ToggleButton object) { + return object.mCurProperty; + } + + @Override + public void set(ToggleButton object, AnimatorProperty value) { + object.setAnimatorProperty(value); + } + }; + + + /** + * @author ThinkPad + */ + public interface OnToggleChanged { + /** + * @param on + */ + public void onToggle(boolean on); + } + + + public void setOnToggleChanged(OnToggleChanged onToggleChanged) { + listener = onToggleChanged; + } +} diff --git a/app/src/main/java/net/oschina/app/interf/ICallbackResult.java b/app/src/main/java/net/oschina/app/interf/ICallbackResult.java deleted file mode 100644 index 929f80c080c5fbf696a60f6dd8bf92a0662e9c1a..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/interf/ICallbackResult.java +++ /dev/null @@ -1,12 +0,0 @@ -package net.oschina.app.interf; - -/** - * @author FireAnt(http://my.oschina.net/LittleDY) - * @version 创建时间:2014年11月18日 上午11:18:28 - * - */ - -public interface ICallbackResult { - - public void OnBackResult(Object s); -} diff --git a/app/src/main/java/net/oschina/app/interf/OnTabReselectListener.java b/app/src/main/java/net/oschina/app/interf/OnTabReselectListener.java index ca491922c7a6e173b6b34fed82729cb9252f42e3..b832d866213df2b1a3c651338006abce71791224 100644 --- a/app/src/main/java/net/oschina/app/interf/OnTabReselectListener.java +++ b/app/src/main/java/net/oschina/app/interf/OnTabReselectListener.java @@ -1,12 +1,12 @@ package net.oschina.app.interf; -/** +/** * 当tabHost再次被点击时 + * * @author FireAnt(http://my.oschina.net/LittleDY) - * @version 创建时间:2014年11月17日 上午11:00:15 - * + * @version 创建时间:2014年11月17日 上午11:00:15 */ public interface OnTabReselectListener { - - public void onTabReselect(); + + void onTabReselect(); } diff --git a/app/src/main/java/net/oschina/app/service/DownloadService.java b/app/src/main/java/net/oschina/app/service/DownloadService.java deleted file mode 100644 index 9da874a9cdb3a09f3c8d552b865bbce5ad5a3657..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/service/DownloadService.java +++ /dev/null @@ -1,302 +0,0 @@ -package net.oschina.app.service; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; - -import net.oschina.app.AppConfig; -import net.oschina.app.R; -import net.oschina.app.interf.ICallbackResult; -import net.oschina.app.ui.MainActivity; -import net.oschina.app.util.StringUtils; -import net.oschina.app.util.TDevice; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.os.Binder; -import android.os.Handler; -import android.os.IBinder; -import android.os.Message; -import android.widget.RemoteViews; - -/** - * download service - * - * @author FireAnt(http://my.oschina.net/LittleDY) - * @created 2014年11月18日 下午3:02:36 - * - */ -public class DownloadService extends Service { - - public static final String BUNDLE_KEY_DOWNLOAD_URL = "download_url"; - - public static final String BUNDLE_KEY_TITLE = "title"; - - private final String tag = "download"; - private static final int NOTIFY_ID = 0; - private int progress; - private NotificationManager mNotificationManager; - private boolean canceled; - - private String downloadUrl; - - private String mTitle = "正在下载%s"; - - private String saveFileName = AppConfig.DEFAULT_SAVE_FILE_PATH; - - private ICallbackResult callback; - - private DownloadBinder binder; - - private boolean serviceIsDestroy = false; - - private Context mContext = this; - - private Thread downLoadThread; - - private Notification mNotification; - - private Handler mHandler = new Handler() { - - @Override - public void handleMessage(Message msg) { - // TODO Auto-generated method stub - super.handleMessage(msg); - switch (msg.what) { - case 0: - // 下载完毕 - mNotificationManager.cancel(NOTIFY_ID); - installApk(); - break; - case 2: - // 取消通知 - mNotificationManager.cancel(NOTIFY_ID); - break; - case 1: - int rate = msg.arg1; - if (rate < 100) { - RemoteViews contentview = mNotification.contentView; - contentview.setTextViewText(R.id.tv_download_state, mTitle + "(" + rate - + "%" + ")"); - contentview.setProgressBar(R.id.pb_download, 100, rate, - false); - } else { - // 下载完毕后变换通知形式 - mNotification.flags = Notification.FLAG_AUTO_CANCEL; - mNotification.contentView = null; - Intent intent = new Intent(mContext, MainActivity.class); - // 告知已完成 - intent.putExtra("completed", "yes"); - // 更新参数,注意flags要使用FLAG_UPDATE_CURRENT - PendingIntent contentIntent = PendingIntent.getActivity( - mContext, 0, intent, - PendingIntent.FLAG_UPDATE_CURRENT); -// mNotification.setLatestEventInfo(mContext, "下载完成", -// "文件已下载完毕", contentIntent); - serviceIsDestroy = true; - stopSelf();// 停掉服务自身 - } - mNotificationManager.notify(NOTIFY_ID, mNotification); - break; - } - } - }; - - @Override - public IBinder onBind(Intent intent) { - downloadUrl = intent.getStringExtra(BUNDLE_KEY_DOWNLOAD_URL); - saveFileName = saveFileName + getSaveFileName(downloadUrl); - mTitle = String.format(mTitle, intent.getStringExtra(BUNDLE_KEY_TITLE)); - return binder; - } - - private String getSaveFileName(String downloadUrl) { - if (downloadUrl == null || StringUtils.isEmpty(downloadUrl)) { - return ""; - } - return downloadUrl.substring(downloadUrl.lastIndexOf("/")); - } - - @Override - public void onCreate() { - super.onCreate(); - binder = new DownloadBinder(); - mNotificationManager = (NotificationManager) getSystemService(android.content.Context.NOTIFICATION_SERVICE); - stopForeground(true);// 这个不确定是否有作用 - } - - private void startDownload() { - canceled = false; - downloadApk(); - } - - /** - * 创建通知 - */ - private void setUpNotification() { - int icon = R.drawable.ic_notification; - CharSequence tickerText = "准备下载"; - long when = System.currentTimeMillis(); - mNotification = new Notification(icon, tickerText, when); - ; - // 放置在"正在运行"栏目中 - mNotification.flags = Notification.FLAG_ONGOING_EVENT; - - RemoteViews contentView = new RemoteViews(getPackageName(), - R.layout.download_notification_show); - contentView.setTextViewText(R.id.tv_download_state, mTitle); - // 指定个性化视图 - mNotification.contentView = contentView; - - Intent intent = new Intent(this, MainActivity.class); - PendingIntent contentIntent = PendingIntent.getActivity(this, 0, - intent, PendingIntent.FLAG_UPDATE_CURRENT); - - // 指定内容意图 - mNotification.contentIntent = contentIntent; - mNotificationManager.notify(NOTIFY_ID, mNotification); - } - - private void downloadApk() { - downLoadThread = new Thread(mdownApkRunnable); - downLoadThread.start(); - } - - /** - * 安装apk - */ - private void installApk() { - File apkfile = new File(saveFileName); - if (!apkfile.exists()) { - return; - } - TDevice.installAPK(mContext, apkfile); - } - - private Runnable mdownApkRunnable = new Runnable() { - @Override - public void run() { - File file = new File(AppConfig.DEFAULT_SAVE_FILE_PATH); - if (!file.exists()) { - file.mkdirs(); - } - String apkFile = saveFileName; - File saveFile = new File(apkFile); - try { - downloadUpdateFile(downloadUrl, saveFile); - } catch (Exception e) { - e.printStackTrace(); - } - } - }; - - public long downloadUpdateFile(String downloadUrl, File saveFile) - throws Exception { - int downloadCount = 0; - int currentSize = 0; - long totalSize = 0; - int updateTotalSize = 0; - - HttpURLConnection httpConnection = null; - InputStream is = null; - FileOutputStream fos = null; - - try { - URL url = new URL(downloadUrl); - httpConnection = (HttpURLConnection) url.openConnection(); - httpConnection - .setRequestProperty("User-Agent", "PacificHttpClient"); - if (currentSize > 0) { - httpConnection.setRequestProperty("RANGE", "bytes=" - + currentSize + "-"); - } - httpConnection.setConnectTimeout(10000); - httpConnection.setReadTimeout(20000); - updateTotalSize = httpConnection.getContentLength(); - if (httpConnection.getResponseCode() == 404) { - throw new Exception("fail!"); - } - is = httpConnection.getInputStream(); - fos = new FileOutputStream(saveFile, false); - byte buffer[] = new byte[1024]; - int readsize = 0; - while ((readsize = is.read(buffer)) > 0) { - fos.write(buffer, 0, readsize); - totalSize += readsize; - // 为了防止频繁的通知导致应用吃紧,百分比增加10才通知一次 - if ((downloadCount == 0) - || (int) (totalSize * 100 / updateTotalSize) - 10 >= downloadCount) { - downloadCount += 10; - // 更新进度 - Message msg = mHandler.obtainMessage(); - msg.what = 1; - msg.arg1 = downloadCount; - mHandler.sendMessage(msg); - if (callback != null) - callback.OnBackResult(progress); - } - } - - // 下载完成通知安装 - mHandler.sendEmptyMessage(0); - // 下载完了,cancelled也要设置 - canceled = true; - - } finally { - if (httpConnection != null) { - httpConnection.disconnect(); - } - if (is != null) { - is.close(); - } - if (fos != null) { - fos.close(); - } - } - return totalSize; - } - - public class DownloadBinder extends Binder { - public void start() { - if (downLoadThread == null || !downLoadThread.isAlive()) { - progress = 0; - setUpNotification(); - new Thread() { - public void run() { - // 下载 - startDownload(); - }; - }.start(); - } - } - - public void cancel() { - canceled = true; - } - - public int getProgress() { - return progress; - } - - public boolean isCanceled() { - return canceled; - } - - public boolean serviceIsDestroy() { - return serviceIsDestroy; - } - - public void cancelNotification() { - mHandler.sendEmptyMessage(2); - } - - public void addCallback(ICallbackResult callback) { - DownloadService.this.callback = callback; - } - } -} diff --git a/app/src/main/java/net/oschina/app/service/INoticeService.aidl b/app/src/main/java/net/oschina/app/service/INoticeService.aidl deleted file mode 100644 index fcd7d7b32e3f0f2b404384036f62b9e36eb2795d..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/service/INoticeService.aidl +++ /dev/null @@ -1,8 +0,0 @@ -package net.oschina.app.service; - -interface INoticeService -{ - void scheduleNotice(); - void requestNotice(); - void clearNotice(int uid,int type); -} \ No newline at end of file diff --git a/app/src/main/java/net/oschina/app/service/NoticeService.java b/app/src/main/java/net/oschina/app/service/NoticeService.java deleted file mode 100644 index 3a5b08dab6bf017240505e2a529cac39e195ca15..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/service/NoticeService.java +++ /dev/null @@ -1,308 +0,0 @@ -package net.oschina.app.service; - -import java.io.ByteArrayInputStream; -import java.lang.ref.WeakReference; - -import net.oschina.app.AppConfig; -import net.oschina.app.AppContext; -import net.oschina.app.R; -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.bean.Constants; -import net.oschina.app.bean.Notice; -import net.oschina.app.bean.NoticeDetail; -import net.oschina.app.bean.Result; -import net.oschina.app.bean.ResultBean; -import net.oschina.app.broadcast.AlarmReceiver; -import net.oschina.app.ui.MainActivity; -import net.oschina.app.util.UIHelper; -import net.oschina.app.util.XmlUtils; - -import cz.msebera.android.httpclient.Header; -import android.app.AlarmManager; -import android.app.Notification; -import android.app.PendingIntent; -import android.app.Service; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.res.Resources; -import android.net.Uri; -import android.os.IBinder; -import android.os.RemoteException; -import android.support.v4.app.NotificationCompat; -import android.support.v4.app.NotificationManagerCompat; - -import com.loopj.android.http.AsyncHttpResponseHandler; - -public class NoticeService extends Service { - public static final String INTENT_ACTION_GET = "net.oschina.app.service.GET_NOTICE"; - public static final String INTENT_ACTION_CLEAR = "net.oschina.app.service.CLEAR_NOTICE"; - public static final String INTENT_ACTION_BROADCAST = "net.oschina.app.service.BROADCAST"; - public static final String INTENT_ACTION_SHUTDOWN = "net.oschina.app.service.SHUTDOWN"; - public static final String INTENT_ACTION_REQUEST = "net.oschina.app.service.REQUEST"; - public static final String BUNDLE_KEY_TPYE = "bundle_key_type"; - - private static final long INTERVAL = 1000 * 120; - private AlarmManager mAlarmMgr; - - private Notice mNotice; - - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (Constants.INTENT_ACTION_NOTICE.equals(action)) { - Notice notice = (Notice) intent.getSerializableExtra("notice_bean"); - int atmeCount = notice.getAtmeCount();// @我 - int msgCount = notice.getMsgCount();// 私信 - int reviewCount = notice.getReviewCount();// 评论 - int newFansCount = notice.getNewFansCount();// 新粉丝 - int newLikeCount = notice.getNewLikeCount();// 点赞数 - int activeCount = atmeCount + reviewCount + msgCount - + newFansCount + newLikeCount; - if (activeCount == 0) { - NotificationManagerCompat.from(NoticeService.this).cancel( - R.string.you_have_news_messages); - } - } else if (INTENT_ACTION_BROADCAST.equals(action)) { - if (mNotice != null) { - UIHelper.sendBroadCast(NoticeService.this, mNotice); - } - } else if (INTENT_ACTION_SHUTDOWN.equals(action)) { - stopSelf(); - } else if (INTENT_ACTION_REQUEST.equals(action)) { - requestNotice(); - } - } - }; - - @Override - public IBinder onBind(Intent intent) { - return mBinder; - } - - @Override - public void onCreate() { - super.onCreate(); - mAlarmMgr = (AlarmManager) getSystemService(ALARM_SERVICE); - startRequestAlarm(); - requestNotice(); - - IntentFilter filter = new IntentFilter(INTENT_ACTION_BROADCAST); - filter.addAction(Constants.INTENT_ACTION_NOTICE); - filter.addAction(INTENT_ACTION_SHUTDOWN); - filter.addAction(INTENT_ACTION_REQUEST); - registerReceiver(mReceiver, filter); - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - return super.onStartCommand(intent, flags, startId); - } - - @Override - public void onDestroy() { - cancelRequestAlarm(); - unregisterReceiver(mReceiver); - super.onDestroy(); - } - - private void startRequestAlarm() { - cancelRequestAlarm(); - // 从1秒后开始,每隔2分钟执行getOperationIntent() - mAlarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, - System.currentTimeMillis() + 1000, INTERVAL, - getOperationIntent()); - } - - /** - * 即使启动PendingIntent的原进程结束了的话,PendingIntent本身仍然还存在,可在其他进程( - * PendingIntent被递交到的其他程序)中继续使用. - * 如果我在从系统中提取一个PendingIntent的,而系统中有一个和你描述的PendingIntent对等的PendingInent, - * 那么系统会直接返回和该PendingIntent其实是同一token的PendingIntent, - * 而不是一个新的token和PendingIntent。然而你在从提取PendingIntent时,通过FLAG_CANCEL_CURRENT参数, - * 让这个老PendingIntent的先cancel()掉,这样得到的pendingInten和其token的就是新的了。 - */ - private void cancelRequestAlarm() { - mAlarmMgr.cancel(getOperationIntent()); - } - - /** - * OSC采用轮询方式实现消息推送
    - * 每次被调用都去执行一次{@link #AlarmReceiver}onReceive()方法 - * - * @return - */ - private PendingIntent getOperationIntent() { - Intent intent = new Intent(this, AlarmReceiver.class); - PendingIntent operation = PendingIntent.getBroadcast(this, 0, intent, - PendingIntent.FLAG_UPDATE_CURRENT); - return operation; - } - - private void clearNotice(int uid, int type) { - OSChinaApi.clearNotice(uid, type, mClearNoticeHandler); - } - - private int lastNotifiyCount; - - private void notification(Notice notice) { - int atmeCount = notice.getAtmeCount(); - int msgCount = notice.getMsgCount(); - int reviewCount = notice.getReviewCount(); - int newFansCount = notice.getNewFansCount(); - int newLikeCount = notice.getNewLikeCount(); - - int count = atmeCount + msgCount + reviewCount + newFansCount + newLikeCount; - - if (count == 0) { - lastNotifiyCount = 0; - NotificationManagerCompat.from(this).cancel( - R.string.you_have_news_messages); - return; - } - if (count == lastNotifiyCount) - return; - - lastNotifiyCount = count; - - Resources res = getResources(); - String contentTitle = res.getString(R.string.you_have_news_messages, - count); - String contentText; - StringBuffer sb = new StringBuffer(); - if (atmeCount > 0) { - sb.append(getString(R.string.atme_count, atmeCount)).append(" "); - } - if (msgCount > 0) { - sb.append(getString(R.string.msg_count, msgCount)).append(" "); - } - if (reviewCount > 0) { - sb.append(getString(R.string.review_count, reviewCount)) - .append(" "); - } - if (newFansCount > 0) { - sb.append(getString(R.string.fans_count, newFansCount)); - } - if (newLikeCount > 0) { - sb.append(getString(R.string.like_count, newLikeCount)); - } - contentText = sb.toString(); - - Intent intent = new Intent(this, MainActivity.class); - intent.putExtra("NOTICE", true); - - PendingIntent pi = PendingIntent.getActivity(this, 1000, intent, - PendingIntent.FLAG_CANCEL_CURRENT); - - NotificationCompat.Builder builder = new NotificationCompat.Builder( - this).setTicker(contentTitle).setContentTitle(contentTitle) - .setContentText(contentText).setAutoCancel(true) - .setContentIntent(pi).setSmallIcon(R.drawable.ic_notification); - - if (AppContext.get(AppConfig.KEY_NOTIFICATION_SOUND, true)) { - builder.setSound(Uri.parse("android.resource://" - + AppContext.getInstance().getPackageName() + "/" - + R.raw.notificationsound)); - } - if (AppContext.get(AppConfig.KEY_NOTIFICATION_VIBRATION, true)) { - long[] vibrate = { 0, 10, 20, 30 }; - builder.setVibrate(vibrate); - } - - Notification notification = builder.build(); - - NotificationManagerCompat.from(this).notify( - R.string.you_have_news_messages, notification); - } - - private final AsyncHttpResponseHandler mGetNoticeHandler = new AsyncHttpResponseHandler() { - - @Override - public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { - try { - Notice notice = XmlUtils.toBean(NoticeDetail.class, - arg2).getNotice(); - if (notice != null) { - UIHelper.sendBroadCast(NoticeService.this, notice); - if (AppContext.get(AppConfig.KEY_NOTIFICATION_ACCEPT, true)) { - notification(notice); - } - mNotice = notice; - } else { -// ResultBean resultBean = XmlUtils.toBean(ResultBean.class, arg2); -// if (resultBean != null && resultBean.getResult() != null) { -// AppContext appContext = AppContext.getInstance(); -// if (appContext != null) { -// appContext.Logout(); -// } -// } - } - } catch (Exception e) { - e.printStackTrace(); - onFailure(arg0, arg1, arg2, e); - } - }; - - @Override - public void onFailure(int arg0, Header[] arg1, byte[] arg2, - Throwable arg3) { - arg3.printStackTrace(); - } - }; - - private final AsyncHttpResponseHandler mClearNoticeHandler = new AsyncHttpResponseHandler() { - - @Override - public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { - try { - ResultBean rsb = XmlUtils.toBean(ResultBean.class, - new ByteArrayInputStream(arg2)); - Result res = rsb.getResult(); - if (res.OK() && rsb.getNotice() != null) { - mNotice = rsb.getNotice(); - UIHelper.sendBroadCast(NoticeService.this, rsb.getNotice()); - } - } catch (Exception e) { - e.printStackTrace(); - } - } - - @Override - public void onFailure(int arg0, Header[] arg1, byte[] arg2, - Throwable arg3) {} - }; - - /** - * 请求是否有新通知 - */ - private void requestNotice() { - OSChinaApi.getNotices(mGetNoticeHandler); - } - - private static class ServiceStub extends INoticeService.Stub { - WeakReference mService; - - ServiceStub(NoticeService service) { - mService = new WeakReference(service); - } - - @Override - public void clearNotice(int uid, int type) throws RemoteException { - mService.get().clearNotice(uid, type); - } - - @Override - public void scheduleNotice() throws RemoteException { - mService.get().startRequestAlarm(); - } - - @Override - public void requestNotice() throws RemoteException { - mService.get().requestNotice(); - } - } - - private final IBinder mBinder = new ServiceStub(this); -} diff --git a/app/src/main/java/net/oschina/app/service/NoticeUtils.java b/app/src/main/java/net/oschina/app/service/NoticeUtils.java deleted file mode 100644 index 9d836947986baae701252c91573ecd82f08b0b18..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/service/NoticeUtils.java +++ /dev/null @@ -1,116 +0,0 @@ -package net.oschina.app.service; - -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.os.RemoteException; -import android.util.Log; - -import net.oschina.app.AppConfig; -import net.oschina.app.AppContext; -import net.oschina.app.util.TLog; - -import java.util.HashMap; - -public class NoticeUtils { - - public static INoticeService sService = null; - private static HashMap sConnectionMap = new HashMap(); - - public static boolean bindToService(Context context) { - return bindToService(context, null); - } - - public static boolean bindToService(Context context, - ServiceConnection callback) { - context.startService(new Intent(context, NoticeService.class)); - ServiceBinder sb = new ServiceBinder(callback); - sConnectionMap.put(context, sb); - return context.bindService( - (new Intent()).setClass(context, NoticeService.class), sb, 0); - } - - public static void unbindFromService(Context context) { - ServiceBinder sb = sConnectionMap.remove(context); - if (sb == null) { - Log.e("MusicUtils", "Trying to unbind for unknown Context"); - return; - } - context.unbindService(sb); - if (sConnectionMap.isEmpty()) { - // presumably there is nobody interested in the service at this - // point, - // so don't hang on to the ServiceConnection - sService = null; - } - } - - public static void clearNotice(int type) { - if (sService != null) { - try { - sService.clearNotice(AppContext.getInstance().getLoginUid(), - type); - } catch (RemoteException e) { - e.printStackTrace(); - } - } - } - - public static void requestNotice(Context context) { - if (sService != null) { - try { - TLog.log("requestNotice..."); - sService.requestNotice(); - } catch (RemoteException e) { - e.printStackTrace(); - } - } else { - context.sendBroadcast(new Intent( - NoticeService.INTENT_ACTION_REQUEST)); - TLog.log("requestNotice,service is null"); - } - } - - public static void scheduleNotice() { - if (sService != null) { - try { - sService.scheduleNotice(); - } catch (RemoteException e) { - e.printStackTrace(); - } - } - } - - private static class ServiceBinder implements ServiceConnection { - ServiceConnection mCallback; - - ServiceBinder(ServiceConnection callback) { - mCallback = callback; - } - - @Override - public void onServiceConnected(ComponentName className, - android.os.IBinder service) { - sService = INoticeService.Stub.asInterface(service); - if (mCallback != null) { - mCallback.onServiceConnected(className, service); - } - } - - @Override - public void onServiceDisconnected(ComponentName className) { - if (mCallback != null) { - mCallback.onServiceDisconnected(className); - } - sService = null; - } - } - - public static void tryToShutDown(Context context) { - if (AppContext.get(AppConfig.KEY_NOTIFICATION_DISABLE_WHEN_EXIT, true)) { - context.sendBroadcast(new Intent( - NoticeService.INTENT_ACTION_SHUTDOWN)); - } - } -} diff --git a/app/src/main/java/net/oschina/app/service/PublicCommentTask.java b/app/src/main/java/net/oschina/app/service/PublicCommentTask.java deleted file mode 100644 index e5eb65c68f212be4fea1af7aa13953fbd7631cc0..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/service/PublicCommentTask.java +++ /dev/null @@ -1,90 +0,0 @@ -package net.oschina.app.service; - -import android.os.Parcel; -import android.os.Parcelable; - -public class PublicCommentTask implements Parcelable { - private int catalog; - private int id; - private int uid; - private String content; - private int isPostToMyZone; - - public PublicCommentTask() { - } - - public PublicCommentTask(Parcel source) { - catalog = source.readInt(); - id = source.readInt(); - uid = source.readInt(); - content = source.readString(); - isPostToMyZone = source.readInt(); - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(catalog); - dest.writeInt(id); - dest.writeInt(uid); - dest.writeString(content); - dest.writeInt(isPostToMyZone); - } - - public int getCatalog() { - return catalog; - } - - public void setCatalog(int catalog) { - this.catalog = catalog; - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public int getUid() { - return uid; - } - - public void setUid(int uid) { - this.uid = uid; - } - - public String getContent() { - return content; - } - - public void setContent(String content) { - this.content = content; - } - - public int getIsPostToMyZone() { - return isPostToMyZone; - } - - public void setIsPostToMyZone(int isPostToMyZone) { - this.isPostToMyZone = isPostToMyZone; - } - - @Override - public int describeContents() { - return 0; - } - - public static final Parcelable.Creator CREATOR = new Creator() { - - @Override - public PublicCommentTask[] newArray(int size) { - return new PublicCommentTask[size]; - } - - @Override - public PublicCommentTask createFromParcel(Parcel source) { - return new PublicCommentTask(source); - } - }; -} diff --git a/app/src/main/java/net/oschina/app/service/ServerTaskService.java b/app/src/main/java/net/oschina/app/service/ServerTaskService.java deleted file mode 100644 index bbb618a3883df4e2fec8029f699f9a55a1befc7f..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/service/ServerTaskService.java +++ /dev/null @@ -1,306 +0,0 @@ -package net.oschina.app.service; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.util.ArrayList; -import java.util.List; - -import net.oschina.app.AppContext; -import net.oschina.app.R; -import net.oschina.app.api.OperationResponseHandler; -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.base.ListBaseAdapter; -import net.oschina.app.bean.Comment; -import net.oschina.app.bean.Result; -import net.oschina.app.bean.ResultBean; -import net.oschina.app.bean.Tweet; -import net.oschina.app.util.XmlUtils; -import android.app.IntentService; -import android.app.Notification; -import android.app.PendingIntent; -import android.content.Intent; -import android.os.Handler; -import android.os.Looper; -import android.support.v4.app.NotificationCompat; -import android.support.v4.app.NotificationManagerCompat; - -public class ServerTaskService extends IntentService { - private static final String SERVICE_NAME = "ServerTaskService"; - public static final String ACTION_PUB_BLOG_COMMENT = "net.oschina.app.ACTION_PUB_BLOG_COMMENT"; - public static final String ACTION_PUB_COMMENT = "net.oschina.app.ACTION_PUB_COMMENT"; - public static final String ACTION_PUB_POST = "net.oschina.app.ACTION_PUB_POST"; - public static final String ACTION_PUB_TWEET = "net.oschina.app.ACTION_PUB_TWEET"; - public static final String ACTION_PUB_SOFTWARE_TWEET = "net.oschina.app.ACTION_PUB_SOFTWARE_TWEET"; - - public static final String KEY_ADAPTER = "adapter"; - - public static final String BUNDLE_PUB_COMMENT_TASK = "BUNDLE_PUB_COMMENT_TASK"; - public static final String BUNDLE_PUB_POST_TASK = "BUNDLE_PUB_POST_TASK"; - public static final String BUNDLE_PUB_TWEET_TASK = "BUNDLE_PUB_TWEET_TASK"; - public static final String BUNDLE_PUB_SOFTWARE_TWEET_TASK = "BUNDLE_PUB_SOFTWARE_TWEET_TASK"; - public static final String KEY_SOFTID = "soft_id"; - - private static final String KEY_COMMENT = "comment_"; - private static final String KEY_TWEET = "tweet_"; - private static final String KEY_SOFTWARE_TWEET = "software_tweet_"; - private static final String KEY_POST = "post_"; - - public static List penddingTasks = new ArrayList(); - - class PublicCommentResponseHandler extends OperationResponseHandler { - - public PublicCommentResponseHandler(Looper looper, Object... args) { - super(looper, args); - } - - @Override - public void onSuccess(int code, ByteArrayInputStream is, Object[] args) - throws Exception { - PublicCommentTask task = (PublicCommentTask) args[0]; - final int id = task.getId() * task.getUid(); - ResultBean resB = XmlUtils.toBean(ResultBean.class, is); - Result res = resB.getResult(); - if (res.OK()) { - final Comment comment = resB.getComment(); - // UIHelper.sendBroadCastCommentChanged(ServerTaskService.this, - // isBlog, task.getId(), task.getCatalog(), - // Comment.OPT_ADD, comment); - notifySimpleNotifycation(id, - getString(R.string.comment_publish_success), - getString(R.string.comment_blog), - getString(R.string.comment_publish_success), false, - true); - removePenddingTask(KEY_COMMENT + id); - } else { - onFailure(100, res.getErrorMessage(), args); - } - } - - @Override - public void onFailure(int code, String errorMessage, Object[] args) { - PublicCommentTask task = (PublicCommentTask) args[0]; - int id = task.getId() * task.getUid(); - notifySimpleNotifycation(id, - getString(R.string.comment_publish_faile), - getString(R.string.comment_blog), - code == 100 ? errorMessage - : getString(R.string.comment_publish_faile), false, - true); - removePenddingTask(KEY_COMMENT + id); - } - - @Override - public void onFinish() { - tryToStopServie(); - } - } - - class PublicTweetResponseHandler extends OperationResponseHandler { - - String key = null; - - public PublicTweetResponseHandler(Looper looper, Object... args) { - super(looper, args); - key = (String) args[1]; - } - - @Override - public void onSuccess(int code, ByteArrayInputStream is, Object[] args) - throws Exception { - Tweet tweet = (Tweet) args[0]; - final int id = tweet.getId(); - Result res = XmlUtils.toBean(ResultBean.class, is).getResult(); - if (res.OK()) { - notifySimpleNotifycation(id, - getString(R.string.tweet_publish_success), - getString(R.string.tweet_public), - getString(R.string.tweet_publish_success), false, true); - new Handler().postDelayed(new Runnable() { - @Override - public void run() { - cancellNotification(id); - } - }, 3000); - removePenddingTask(key + id); - if (tweet.getImageFilePath() != null) { - File imgFile = new File(tweet.getImageFilePath()); - if (imgFile.exists()) { - imgFile.delete(); - } - } - } else { - onFailure(100, res.getErrorMessage(), args); - } - } - - @Override - public void onFailure(int code, String errorMessage, Object[] args) { - Tweet tweet = (Tweet) args[0]; - int id = tweet.getId(); - notifySimpleNotifycation(id, - getString(R.string.tweet_publish_faile), - getString(R.string.tweet_public), - code == 100 ? errorMessage - : getString(R.string.tweet_publish_faile), false, - true); - removePenddingTask(key + id); - } - - @Override - public void onFinish() { - tryToStopServie(); - } - } - - public ServerTaskService() { - this(SERVICE_NAME); - } - - private synchronized void tryToStopServie() { - if (penddingTasks == null || penddingTasks.size() == 0) { - stopSelf(); - } - } - - private synchronized void addPenddingTask(String key) { - penddingTasks.add(key); - } - - private synchronized void removePenddingTask(String key) { - penddingTasks.remove(key); - } - - public ServerTaskService(String name) { - super(name); - } - - @Override - public void onCreate() { - super.onCreate(); - - } - - @Override - protected void onHandleIntent(Intent intent) { - String action = intent.getAction(); - - if (ACTION_PUB_BLOG_COMMENT.equals(action)) { - PublicCommentTask task = intent - .getParcelableExtra(BUNDLE_PUB_COMMENT_TASK); - if (task != null) { - publicBlogComment(task); - } - } else if (ACTION_PUB_COMMENT.equals(action)) { - PublicCommentTask task = intent - .getParcelableExtra(BUNDLE_PUB_COMMENT_TASK); - if (task != null) { - publicComment(task); - } - } else if (ACTION_PUB_POST.equals(action)) { - // Post post = intent.getParcelableExtra(BUNDLE_PUBLIC_POST_TASK); - // if (post != null) { - // publicPost(post); - // } - } else if (ACTION_PUB_TWEET.equals(action)) { - Tweet tweet = intent.getParcelableExtra(BUNDLE_PUB_TWEET_TASK); - if (tweet != null) { - pubTweet(tweet); - } - } else if (ACTION_PUB_SOFTWARE_TWEET.equals(action)) { - Tweet tweet = intent - .getParcelableExtra(BUNDLE_PUB_SOFTWARE_TWEET_TASK); - int softid = intent.getIntExtra(KEY_SOFTID, -1); - if (tweet != null && softid != -1) { - pubSoftWareTweet(tweet, softid); - } - } - } - - private void publicBlogComment(final PublicCommentTask task) { - int id = task.getId() * task.getUid(); - addPenddingTask(KEY_COMMENT + id); - - notifySimpleNotifycation(id, getString(R.string.comment_publishing), - getString(R.string.comment_blog), - getString(R.string.comment_publishing), true, false); - - OSChinaApi.publicBlogComment(task.getId(), task.getUid(), task - .getContent(), new PublicCommentResponseHandler( - getMainLooper(), task, true)); - } - - private void publicComment(final PublicCommentTask task) { - int id = task.getId() * task.getUid(); - addPenddingTask(KEY_COMMENT + id); - - notifySimpleNotifycation(id, getString(R.string.comment_publishing), - getString(R.string.comment_blog), - getString(R.string.comment_publishing), true, false); - - OSChinaApi.publicComment(task.getCatalog(), task.getId(), - task.getUid(), task.getContent(), task.getIsPostToMyZone(), - new PublicCommentResponseHandler(getMainLooper(), task, false)); - } - - // private void publicPost(Post post) { - // post.setId((int) System.currentTimeMillis()); - // int id = post.getId(); - // addPenddingTask(KEY_POST + id); - // notifySimpleNotifycation(id, getString(R.string.post_publishing), - // getString(R.string.post_public), - // getString(R.string.post_publishing), true, false); - // OSChinaApi.publicPost(post, new - // PublicPostResponseHandler(getMainLooper(), - // post)); - // } - // - private void pubTweet(final Tweet tweet) { - tweet.setId((int) System.currentTimeMillis()); - int id = tweet.getId(); - addPenddingTask(KEY_TWEET + id); - notifySimpleNotifycation(id, getString(R.string.tweet_publishing), - getString(R.string.tweet_public), - getString(R.string.tweet_publishing), true, false); - OSChinaApi.pubTweet(tweet, new PublicTweetResponseHandler( - getMainLooper(), tweet, KEY_TWEET)); - } - - private void pubSoftWareTweet(final Tweet tweet, int softid) { - tweet.setId((int) System.currentTimeMillis()); - int id = tweet.getId(); - addPenddingTask(KEY_SOFTWARE_TWEET + id); - notifySimpleNotifycation(id, getString(R.string.tweet_publishing), - getString(R.string.tweet_public), - getString(R.string.tweet_publishing), true, false); - OSChinaApi.pubSoftWareTweet(tweet, softid, - new PublicTweetResponseHandler(getMainLooper(), tweet, - KEY_SOFTWARE_TWEET)); - } - - private void notifySimpleNotifycation(int id, String ticker, String title, - String content, boolean ongoing, boolean autoCancel) { - NotificationCompat.Builder builder = new NotificationCompat.Builder( - this) - .setTicker(ticker) - .setContentTitle(title) - .setContentText(content) - .setAutoCancel(true) - .setOngoing(false) - .setOnlyAlertOnce(true) - .setContentIntent( - PendingIntent.getActivity(this, 0, new Intent(), 0)) - .setSmallIcon(R.drawable.ic_notification); - - // if (AppContext.isNotificationSoundEnable()) { - // builder.setDefaults(Notification.DEFAULT_SOUND); - // } - - Notification notification = builder.build(); - - NotificationManagerCompat.from(this).notify(id, notification); - } - - private void cancellNotification(int id) { - NotificationManagerCompat.from(this).cancel(id); - } -} diff --git a/app/src/main/java/net/oschina/app/service/ServerTaskUtils.java b/app/src/main/java/net/oschina/app/service/ServerTaskUtils.java deleted file mode 100644 index 4ae0f3bbcec62345d0e3a72fc77f9d5738b7ed67..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/service/ServerTaskUtils.java +++ /dev/null @@ -1,31 +0,0 @@ -package net.oschina.app.service; - -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; - -import net.oschina.app.AppContext; -import net.oschina.app.bean.Tweet; - -public class ServerTaskUtils { - - public static void pubTweet(Context context, Tweet tweet) { - Intent intent = new Intent(ServerTaskService.ACTION_PUB_TWEET); - Bundle bundle = new Bundle(); - bundle.putParcelable(ServerTaskService.BUNDLE_PUB_TWEET_TASK, tweet); - intent.putExtras(bundle); - intent.setPackage(AppContext.getInstance().getPackageName()); - context.startService(intent); - } - - public static void pubSoftWareTweet(Context context, Tweet tweet, int softid) { - Intent intent = new Intent(ServerTaskService.ACTION_PUB_SOFTWARE_TWEET); - Bundle bundle = new Bundle(); - bundle.putParcelable(ServerTaskService.BUNDLE_PUB_SOFTWARE_TWEET_TASK, - tweet); - bundle.putInt(ServerTaskService.KEY_SOFTID, softid); - intent.putExtras(bundle); - intent.setPackage(AppContext.getInstance().getPackageName()); - context.startService(intent); - } -} diff --git a/app/src/main/java/net/oschina/app/team/adapter/TeamActiveAdapter.java b/app/src/main/java/net/oschina/app/team/adapter/TeamActiveAdapter.java index 70a89a0c30d6df8e8b1da93958a9d8959a3c4f6e..34b1a83dcab762aa477cce5d1c31b6c936184a99 100644 --- a/app/src/main/java/net/oschina/app/team/adapter/TeamActiveAdapter.java +++ b/app/src/main/java/net/oschina/app/team/adapter/TeamActiveAdapter.java @@ -10,7 +10,7 @@ import android.widget.TextView; import net.oschina.app.R; import net.oschina.app.base.ListBaseAdapter; import net.oschina.app.team.bean.TeamActive; -import net.oschina.app.ui.ImagePreviewActivity; +import net.oschina.app.ui.OSCPhotosActivity; import net.oschina.app.util.BitmapHelper; import net.oschina.app.util.StringUtils; import net.oschina.app.widget.AvatarView; @@ -73,10 +73,10 @@ public class TeamActiveAdapter extends ListBaseAdapter { holder.tv_name.setText(data.getAuthor().getName()); setContent(holder.tv_content, stripTags(data.getBody().getTitle())); - String date = StringUtils.friendly_time2(data.getCreateTime()); + String date = StringUtils.formatDayWeek(data.getCreateTime()); String preDate = ""; if (position > 0) { - preDate = StringUtils.friendly_time2(mDatas.get(position - 1) + preDate = StringUtils.formatDayWeek(mDatas.get(position - 1) .getCreateTime()); } if (preDate.equals(date)) { @@ -87,7 +87,7 @@ public class TeamActiveAdapter extends ListBaseAdapter { } holder.tv_content.setMaxLines(3); - holder.tv_date.setText(StringUtils.friendly_time(data.getCreateTime())); + holder.tv_date.setText(StringUtils.formatSomeAgo(data.getCreateTime())); holder.tv_commit.setText(data.getReply()); String imgPath = data.getBody().getImage(); @@ -143,8 +143,7 @@ public class TeamActiveAdapter extends ListBaseAdapter { pic.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - ImagePreviewActivity.showImagePrivew(context, 0, - new String[]{url}); + OSCPhotosActivity.showImagePreview(context, url); } }); } diff --git a/app/src/main/java/net/oschina/app/team/adapter/TeamDiaryListAdapter.java b/app/src/main/java/net/oschina/app/team/adapter/TeamDiaryListAdapter.java index 774f52f69ea45f00371f8b34ad3c248cfba0d83e..b9f9d6766da212c6cac1af04b8046973bd470abe 100644 --- a/app/src/main/java/net/oschina/app/team/adapter/TeamDiaryListAdapter.java +++ b/app/src/main/java/net/oschina/app/team/adapter/TeamDiaryListAdapter.java @@ -74,7 +74,7 @@ public class TeamDiaryListAdapter extends BaseAdapter { } holder.iv_face.setAvatarUrl(data.getAuthor().getPortrait()); holder.tv_author.setText(data.getAuthor().getName()); - holder.tv_date.setText(StringUtils.friendly_time(data.getCreateTime())); + holder.tv_date.setText(StringUtils.formatSomeAgo(data.getCreateTime())); holder.tv_count.setText(data.getReply() + ""); holder.tv_title.setText(Html.fromHtml(data.getTitle()).toString() .trim()); diff --git a/app/src/main/java/net/oschina/app/team/adapter/TeamDiscussAdapter.java b/app/src/main/java/net/oschina/app/team/adapter/TeamDiscussAdapter.java index 31fff0a4ac7d4f7873011a18e2f5e89bae32da03..b619fffc43a936783347afd3a30489132560559f 100755 --- a/app/src/main/java/net/oschina/app/team/adapter/TeamDiscussAdapter.java +++ b/app/src/main/java/net/oschina/app/team/adapter/TeamDiscussAdapter.java @@ -12,7 +12,7 @@ import net.oschina.app.util.StringUtils; import net.oschina.app.widget.AvatarView; import butterknife.ButterKnife; -import butterknife.InjectView; +import butterknife.Bind; /** * team 讨论区帖子 @@ -24,24 +24,24 @@ public class TeamDiscussAdapter extends ListBaseAdapter { static class ViewHolder { - @InjectView(R.id.tv_title) + @Bind(R.id.tv_title) TextView title; - @InjectView(R.id.tv_description) + @Bind(R.id.tv_description) TextView description; - @InjectView(R.id.tv_author) + @Bind(R.id.tv_author) TextView author; - @InjectView(R.id.tv_date) + @Bind(R.id.tv_date) TextView time; - @InjectView(R.id.tv_count) + @Bind(R.id.tv_count) TextView comment_count; - @InjectView(R.id.tv_vote_up) + @Bind(R.id.tv_vote_up) TextView vote_up; - @InjectView(R.id.iv_face) + @Bind(R.id.iv_face) public AvatarView face; public ViewHolder(View view) { - ButterKnife.inject(this, view); + ButterKnife.bind(this, view); } } @@ -65,12 +65,10 @@ public class TeamDiscussAdapter extends ListBaseAdapter { vh.title.setText(item.getTitle()); String body = item.getBody().trim(); vh.description.setVisibility(View.GONE); - if (null != body || !StringUtils.isEmpty(body)) { - vh.description.setVisibility(View.VISIBLE); - vh.description.setText(HTMLUtil.replaceTag(item.getBody()).trim()); - } + vh.description.setVisibility(View.VISIBLE); + vh.description.setText(HTMLUtil.replaceTag(body)); vh.author.setText(item.getAuthor().getName()); - vh.time.setText(StringUtils.friendly_time(item.getCreateTime())); + vh.time.setText(StringUtils.formatSomeAgo(item.getCreateTime())); vh.vote_up.setText(item.getVoteUp() + ""); vh.comment_count.setText(item.getAnswerCount() + ""); return convertView; diff --git a/app/src/main/java/net/oschina/app/team/adapter/TeamIssueAdapter.java b/app/src/main/java/net/oschina/app/team/adapter/TeamIssueAdapter.java index 265f6a650465667038d842886feb1b26b854f8f2..5780fe8bef5f8e6f9aca8f876e30189bdde10823 100644 --- a/app/src/main/java/net/oschina/app/team/adapter/TeamIssueAdapter.java +++ b/app/src/main/java/net/oschina/app/team/adapter/TeamIssueAdapter.java @@ -18,7 +18,7 @@ import java.text.SimpleDateFormat; import java.util.Date; import butterknife.ButterKnife; -import butterknife.InjectView; +import butterknife.Bind; /** * 任务列表适配器 @@ -47,10 +47,10 @@ public class TeamIssueAdapter extends ListBaseAdapter { vh.title.setText(item.getTitle()); - String date = StringUtils.friendly_time2(item.getCreateTime()); + String date = StringUtils.formatDayWeek(item.getCreateTime()); String preDate = ""; if (position > 0) { - preDate = StringUtils.friendly_time2(mDatas.get(position - 1) + preDate = StringUtils.formatDayWeek(mDatas.get(position - 1) .getCreateTime()); } if (preDate.equals(date)) { @@ -75,7 +75,7 @@ public class TeamIssueAdapter extends ListBaseAdapter { vh.touser.setText(item.getToUser().getName()); } - vh.time.setText(StringUtils.friendly_time(item.getCreateTime())); + vh.time.setText(StringUtils.formatSomeAgo(item.getCreateTime())); vh.comment.setText(item.getReplyCount() + ""); if (item.getProject() != null && item.getProject().getGit() != null) { @@ -163,37 +163,37 @@ public class TeamIssueAdapter extends ListBaseAdapter { } static class ViewHolder { - @InjectView(R.id.iv_issue_state) + @Bind(R.id.iv_issue_state) TextView state; - @InjectView(R.id.tv_title) + @Bind(R.id.tv_title) TextView title; - @InjectView(R.id.iv_issue_source) + @Bind(R.id.iv_issue_source) TextView issueSource; - @InjectView(R.id.tv_project) + @Bind(R.id.tv_project) TextView project; - @InjectView(R.id.tv_attachments) + @Bind(R.id.tv_attachments) TextView attachments;// 附件 - @InjectView(R.id.tv_childissues) + @Bind(R.id.tv_childissues) TextView childissues;// 子任务 - @InjectView(R.id.tv_relations) + @Bind(R.id.tv_relations) TextView relations;// 关联任务 - @InjectView(R.id.tv_accept_time) + @Bind(R.id.tv_accept_time) TextView accept_time; - @InjectView(R.id.tv_author) + @Bind(R.id.tv_author) TextView author; - @InjectView(R.id.tv_to) + @Bind(R.id.tv_to) TextView to; - @InjectView(R.id.tv_touser) + @Bind(R.id.tv_touser) TextView touser; - @InjectView(R.id.tv_time) + @Bind(R.id.tv_time) TextView time; - @InjectView(R.id.tv_comment_count) + @Bind(R.id.tv_comment_count) TextView comment; - @InjectView(R.id.title) + @Bind(R.id.title) TextView title_line; public ViewHolder(View view) { - ButterKnife.inject(this, view); + ButterKnife.bind(this, view); } } } diff --git a/app/src/main/java/net/oschina/app/team/adapter/TeamIssueCatalogAdapter.java b/app/src/main/java/net/oschina/app/team/adapter/TeamIssueCatalogAdapter.java index d54eef8781ccb2d15b1ec97938f819b5dc970678..42e04d53f15fc5cce99958d7a6064a8a9c62e36e 100644 --- a/app/src/main/java/net/oschina/app/team/adapter/TeamIssueCatalogAdapter.java +++ b/app/src/main/java/net/oschina/app/team/adapter/TeamIssueCatalogAdapter.java @@ -1,14 +1,16 @@ package net.oschina.app.team.adapter; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + import net.oschina.app.R; import net.oschina.app.base.ListBaseAdapter; import net.oschina.app.team.bean.TeamIssueCatalog; import net.oschina.app.util.StringUtils; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; + +import butterknife.Bind; import butterknife.ButterKnife; -import butterknife.InjectView; /** * TeamIssueCatalogAdapter.java @@ -49,15 +51,15 @@ public class TeamIssueCatalogAdapter extends ListBaseAdapter { static class ViewHolder { - @InjectView(R.id.tv_team_issue_catalog_title) + @Bind(R.id.tv_team_issue_catalog_title) TextView title; - @InjectView(R.id.tv_team_issue_catalog_desc) + @Bind(R.id.tv_team_issue_catalog_desc) TextView description; - @InjectView(R.id.tv_team_issue_catalog_state) + @Bind(R.id.tv_team_issue_catalog_state) TextView state; public ViewHolder(View view) { - ButterKnife.inject(this, view); + ButterKnife.bind(this, view); } } } diff --git a/app/src/main/java/net/oschina/app/team/adapter/TeamProjectListAdapter.java b/app/src/main/java/net/oschina/app/team/adapter/TeamProjectListAdapter.java index 843a260854400fa0db52bd88f37ae7c6daf15940..287dcf595685666451b50b3f296ba1901351a17e 100644 --- a/app/src/main/java/net/oschina/app/team/adapter/TeamProjectListAdapter.java +++ b/app/src/main/java/net/oschina/app/team/adapter/TeamProjectListAdapter.java @@ -14,7 +14,7 @@ import java.util.ArrayList; import java.util.List; import butterknife.ButterKnife; -import butterknife.InjectView; +import butterknife.Bind; /** * 团队项目适配器 @@ -88,13 +88,13 @@ public class TeamProjectListAdapter extends BaseAdapter { } public static class ViewHolder { - @InjectView(R.id.iv_source) + @Bind(R.id.iv_source) TextView source; - @InjectView(R.id.tv_project_name) + @Bind(R.id.tv_project_name) TextView name; public ViewHolder(View view) { - ButterKnife.inject(this, view); + ButterKnife.bind(this, view); } } diff --git a/app/src/main/java/net/oschina/app/team/adapter/TeamProjectListAdapterNew.java b/app/src/main/java/net/oschina/app/team/adapter/TeamProjectListAdapterNew.java index 2654a37f66ac823ede90e07b311ecc0588f103dc..0e2217192fe3f4b6a563e83b037271275b6f5860 100644 --- a/app/src/main/java/net/oschina/app/team/adapter/TeamProjectListAdapterNew.java +++ b/app/src/main/java/net/oschina/app/team/adapter/TeamProjectListAdapterNew.java @@ -11,7 +11,7 @@ import net.oschina.app.team.bean.TeamProject; import net.oschina.app.util.TypefaceUtils; import butterknife.ButterKnife; -import butterknife.InjectView; +import butterknife.Bind; /** * 团队项目适配器 @@ -53,22 +53,24 @@ public class TeamProjectListAdapterNew extends ListBaseAdapter { TypefaceUtils.setTypeface(tvSource, R.string.fa_list_alt); } - vh.name.setText(item.getGit().getOwnerName() + " / " + item.getGit().getName()); - vh.issue.setText(item.getIssue().getOpened() + "/" + item.getIssue().getAll()); + vh.name.setText(String.format("%s / %s", item.getGit().getOwnerName(), item.getGit() + .getName())); + vh.issue.setText(String.format("%d/%d", item.getIssue().getOpened(), item.getIssue() + .getAll())); return convertView; } public static class ViewHolder { - @InjectView(R.id.iv_source) + @Bind(R.id.iv_source) TextView source; - @InjectView(R.id.tv_project_name) + @Bind(R.id.tv_project_name) TextView name; - @InjectView(R.id.tv_project_issue) + @Bind(R.id.tv_project_issue) TextView issue; public ViewHolder(View view) { - ButterKnife.inject(this, view); + ButterKnife.bind(this, view); } } diff --git a/app/src/main/java/net/oschina/app/team/adapter/TeamProjectMemberAdapter.java b/app/src/main/java/net/oschina/app/team/adapter/TeamProjectMemberAdapter.java index 2334c5908dba95f909883c810fdd21e9c870469f..1b0461de290eb9231d731a2bafa95426ffa2387a 100644 --- a/app/src/main/java/net/oschina/app/team/adapter/TeamProjectMemberAdapter.java +++ b/app/src/main/java/net/oschina/app/team/adapter/TeamProjectMemberAdapter.java @@ -1,14 +1,16 @@ package net.oschina.app.team.adapter; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + import net.oschina.app.R; import net.oschina.app.base.ListBaseAdapter; import net.oschina.app.team.bean.TeamMember; import net.oschina.app.widget.AvatarView; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; + +import butterknife.Bind; import butterknife.ButterKnife; -import butterknife.InjectView; /** * 团队项目适配器 @@ -42,13 +44,13 @@ public class TeamProjectMemberAdapter extends ListBaseAdapter { } public static class ViewHolder { - @InjectView(R.id.iv_avatar) + @Bind(R.id.iv_avatar) AvatarView avatar; - @InjectView(R.id.tv_name) + @Bind(R.id.tv_name) TextView name; public ViewHolder(View view) { - ButterKnife.inject(this, view); + ButterKnife.bind(this, view); } } diff --git a/app/src/main/java/net/oschina/app/team/adapter/TeamReplyAdapter.java b/app/src/main/java/net/oschina/app/team/adapter/TeamReplyAdapter.java index 93da945975880301ea0ef3381457f07b8669b38d..b2e81c30f6659f6b4e62a7331f416a15af68fc2a 100644 --- a/app/src/main/java/net/oschina/app/team/adapter/TeamReplyAdapter.java +++ b/app/src/main/java/net/oschina/app/team/adapter/TeamReplyAdapter.java @@ -1,6 +1,10 @@ package net.oschina.app.team.adapter; -import java.util.List; +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import android.widget.TextView; import net.oschina.app.R; import net.oschina.app.base.ListBaseAdapter; @@ -9,13 +13,11 @@ import net.oschina.app.util.HTMLUtil; import net.oschina.app.util.StringUtils; import net.oschina.app.widget.AvatarView; import net.oschina.app.widget.TweetTextView; -import android.content.Context; -import android.view.View; -import android.view.ViewGroup; -import android.widget.LinearLayout; -import android.widget.TextView; + +import java.util.List; + +import butterknife.Bind; import butterknife.ButterKnife; -import butterknife.InjectView; /** * 评论适配器 TeamReply.java @@ -42,7 +44,7 @@ public class TeamReplyAdapter extends ListBaseAdapter { vh.name.setText(item.getAuthor().getName()); vh.avatar.setAvatarUrl(item.getAuthor().getPortrait()); setContent(vh.content, HTMLUtil.delHTMLTag(item.getContent())); - vh.time.setText(StringUtils.friendly_time(item.getCreateTime())); + vh.time.setText(StringUtils.formatSomeAgo(item.getCreateTime())); if (StringUtils.isEmpty(item.getAppName())) { vh.from.setVisibility(View.GONE); @@ -84,7 +86,7 @@ public class TeamReplyAdapter extends ListBaseAdapter { TweetTextView content = (TweetTextView) replyItemView.findViewById(R.id.tv_content); setContent(content, HTMLUtil.delHTMLTag(teamReply.getContent())); TextView time = (TextView) replyItemView.findViewById(R.id.tv_time); - time.setText(StringUtils.friendly_time(teamReply.getCreateTime())); + time.setText(StringUtils.formatSomeAgo(teamReply.getCreateTime())); TextView from = (TextView) replyItemView.findViewById(R.id.tv_from); if (StringUtils.isEmpty(teamReply.getAppName())) { from.setVisibility(View.GONE); @@ -99,21 +101,21 @@ public class TeamReplyAdapter extends ListBaseAdapter { static class ViewHolder { - @InjectView(R.id.iv_avatar) + @Bind(R.id.iv_avatar) AvatarView avatar; - @InjectView(R.id.tv_name) + @Bind(R.id.tv_name) TextView name; - @InjectView(R.id.tv_time) + @Bind(R.id.tv_time) TextView time; - @InjectView(R.id.tv_from) + @Bind(R.id.tv_from) TextView from; - @InjectView(R.id.tv_content) + @Bind(R.id.tv_content) TweetTextView content; - @InjectView(R.id.ly_relies) + @Bind(R.id.ly_relies) LinearLayout relies; public ViewHolder(View view) { - ButterKnife.inject(this, view); + ButterKnife.bind(this, view); } } } diff --git a/app/src/main/java/net/oschina/app/team/adapter/TeamSelectMemberAdapter.java b/app/src/main/java/net/oschina/app/team/adapter/TeamSelectMemberAdapter.java index 8b330aa3ea62f2c451b3800c9264bc19a2293fda..3704c7d71b5063eba01d8d20adb6db8c5bf7f2ac 100644 --- a/app/src/main/java/net/oschina/app/team/adapter/TeamSelectMemberAdapter.java +++ b/app/src/main/java/net/oschina/app/team/adapter/TeamSelectMemberAdapter.java @@ -1,29 +1,31 @@ package net.oschina.app.team.adapter; -import java.util.List; - -import net.oschina.app.R; -import net.oschina.app.team.bean.TeamMember; -import net.oschina.app.widget.AvatarView; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; + +import net.oschina.app.R; +import net.oschina.app.team.bean.TeamMember; +import net.oschina.app.widget.AvatarView; + +import java.util.List; + +import butterknife.Bind; import butterknife.ButterKnife; -import butterknife.InjectView; public class TeamSelectMemberAdapter extends BaseAdapter { static class ViewHolder { - @InjectView(R.id.iv_avatar) + @Bind(R.id.iv_avatar) AvatarView aView; - @InjectView(R.id.tv_name) + @Bind(R.id.tv_name) TextView name; ViewHolder(View view) { - ButterKnife.inject(this, view); + ButterKnife.bind(this, view); } } diff --git a/app/src/main/java/net/oschina/app/team/fragment/MyIssueFragment.java b/app/src/main/java/net/oschina/app/team/fragment/MyIssueFragment.java index 3bc9188fdd8e2ec2da5f7bd234cc623cb878fa80..4e023cf9e1e3b2e90cb240c9b5029e6af9f6322e 100644 --- a/app/src/main/java/net/oschina/app/team/fragment/MyIssueFragment.java +++ b/app/src/main/java/net/oschina/app/team/fragment/MyIssueFragment.java @@ -1,11 +1,14 @@ package net.oschina.app.team.fragment; -import java.io.InputStream; -import java.io.Serializable; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.view.View; +import android.widget.AdapterView; -import net.oschina.app.AppContext; import net.oschina.app.api.remote.OSChinaApi; import net.oschina.app.base.BaseListFragment; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.account.AccountHelper; import net.oschina.app.team.adapter.TeamIssueAdapter; import net.oschina.app.team.bean.Team; import net.oschina.app.team.bean.TeamIssue; @@ -14,16 +17,14 @@ import net.oschina.app.team.ui.TeamMainActivity; import net.oschina.app.team.viewpagefragment.MyIssuePagerfragment; import net.oschina.app.util.UIHelper; import net.oschina.app.util.XmlUtils; -import android.graphics.drawable.ColorDrawable; -import android.os.Bundle; -import android.view.View; -import android.widget.AdapterView; + +import java.io.InputStream; +import java.io.Serializable; /** * 我的任务列表界面 - * + * * @author kymjs (https://github.com/kymjs) - * */ public class MyIssueFragment extends BaseListFragment { @@ -62,7 +63,7 @@ public class MyIssueFragment extends BaseListFragment { */ @Override protected String getCacheKeyPrefix() { - return CACHE_KEY_PREFIX + AppContext.getInstance().getLoginUid() + "_" + return CACHE_KEY_PREFIX + AccountHelper.getUserId() + "_" + mTeam.getId() + mCurrentPage + type; } @@ -79,13 +80,12 @@ public class MyIssueFragment extends BaseListFragment { @Override protected void sendRequestData() { - OSChinaApi.getMyIssue(mTeam.getId() + "", AppContext.getInstance() - .getLoginUid() + "", mCurrentPage, type, mHandler); + OSChinaApi.getMyIssue(mTeam.getId() + "", AccountHelper.getUserId() + "", mCurrentPage, type, mHandler); } @Override public void onItemClick(AdapterView parent, View view, int position, - long id) { + long id) { // TODO Auto-generated method stub TeamIssue issue = mAdapter.getItem(position); if (issue != null) { diff --git a/app/src/main/java/net/oschina/app/team/fragment/NoteBookFragment.java b/app/src/main/java/net/oschina/app/team/fragment/NoteBookFragment.java index 50ef5712198d4278684cddd5c35095ae2f08049b..447f862458e3e9fbb852d563c83f416488f0f0e4 100644 --- a/app/src/main/java/net/oschina/app/team/fragment/NoteBookFragment.java +++ b/app/src/main/java/net/oschina/app/team/fragment/NoteBookFragment.java @@ -1,6 +1,25 @@ package net.oschina.app.team.fragment; -import java.util.List; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnTouchListener; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.ImageView; + +import com.loopj.android.http.AsyncHttpResponseHandler; import net.oschina.app.AppContext; import net.oschina.app.R; @@ -11,6 +30,7 @@ import net.oschina.app.bean.NotebookDataList; import net.oschina.app.bean.SimpleBackPage; import net.oschina.app.bean.User; import net.oschina.app.db.NoteDatabase; +import net.oschina.app.improve.account.AccountHelper; import net.oschina.app.team.adapter.NotebookAdapter; import net.oschina.app.ui.empty.EmptyLayout; import net.oschina.app.util.KJAnimations; @@ -22,45 +42,27 @@ import net.oschina.app.widget.KJDragGridView; import net.oschina.app.widget.KJDragGridView.OnDeleteListener; import net.oschina.app.widget.KJDragGridView.OnMoveListener; -import cz.msebera.android.httpclient.Header; -import android.annotation.SuppressLint; -import android.app.Activity; -import android.graphics.Color; -import android.graphics.drawable.ColorDrawable; -import android.os.Bundle; -import android.support.v4.widget.SwipeRefreshLayout; -import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.MotionEvent; -import android.view.View; -import android.view.View.OnTouchListener; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.ImageView; -import butterknife.ButterKnife; -import butterknife.InjectView; +import java.util.List; -import com.loopj.android.http.AsyncHttpResponseHandler; +import butterknife.Bind; +import butterknife.ButterKnife; +import cz.msebera.android.httpclient.Header; /** * 便签列表界面 - * + * * @author kymjs (https://github.com/kymjs) */ public class NoteBookFragment extends BaseFragment implements OnItemClickListener, OnRefreshListener { - @InjectView(R.id.frag_note_list) + @Bind(R.id.frag_note_list) KJDragGridView mGrid; - @InjectView(R.id.frag_note_trash) + @Bind(R.id.frag_note_trash) ImageView mImgTrash; - @InjectView(R.id.swiperefreshlayout) + @Bind(R.id.swiperefreshlayout) SwipeRefreshLayout mSwipeRefreshLayout; - @InjectView(R.id.error_layout) + @Bind(R.id.error_layout) EmptyLayout mEmptyLayout; private NoteDatabase noteDb; @@ -93,12 +95,12 @@ public class NoteBookFragment extends BaseFragment implements @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { + Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); View rootView = inflater.inflate(R.layout.fragment_note, container, false); aty = getActivity(); - ButterKnife.inject(this, rootView); + ButterKnife.bind(this, rootView); initData(); initView(rootView); return rootView; @@ -125,20 +127,20 @@ public class NoteBookFragment extends BaseFragment implements @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case R.id.public_menu_send: - Bundle bundle = new Bundle(); - bundle.putInt(NoteEditFragment.NOTE_FROMWHERE_KEY, - NoteEditFragment.NOTEBOOK_FRAGMENT); - UIHelper.showSimpleBack(getActivity(), SimpleBackPage.NOTE_EDIT, - bundle); - break; + case R.id.public_menu_send: + Bundle bundle = new Bundle(); + bundle.putInt(NoteEditFragment.NOTE_FROMWHERE_KEY, + NoteEditFragment.NOTEBOOK_FRAGMENT); + UIHelper.showSimpleBack(getActivity(), SimpleBackPage.NOTE_EDIT, + bundle); + break; } return true; } @Override public void onItemClick(AdapterView parent, View view, int position, - long id) { + long id) { Bundle bundle = new Bundle(); bundle.putInt(NoteEditFragment.NOTE_FROMWHERE_KEY, NoteEditFragment.NOTEBOOK_ITEM); @@ -150,7 +152,7 @@ public class NoteBookFragment extends BaseFragment implements @Override public void initData() { - user = AppContext.getInstance().getLoginUser(); + user = new User(); controller = new SynchronizeController(); noteDb = new NoteDatabase(aty); datas = noteDb.query();// 查询操作,忽略耗时 @@ -198,7 +200,8 @@ public class NoteBookFragment extends BaseFragment implements } @Override - public void cancleMove() {} + public void cancleMove() { + } }); mSwipeRefreshLayout.setOnTouchListener(new OnTouchListener() { @Override @@ -267,7 +270,7 @@ public class NoteBookFragment extends BaseFragment implements * 未登陆用户不能下拉同步,只能使用本地存储 */ private void setListCanPull() { - if (!AppContext.getInstance().isLogin()) { + if (!AccountHelper.isLogin()) { mSwipeRefreshLayout.setEnabled(false); } else { mSwipeRefreshLayout.setEnabled(true); @@ -330,7 +333,7 @@ public class NoteBookFragment extends BaseFragment implements /** * 删除数据 - * + * * @param index */ private void delete(int index) { @@ -341,11 +344,12 @@ public class NoteBookFragment extends BaseFragment implements new AsyncHttpResponseHandler() { @Override public void onSuccess(int arg0, Header[] arg1, - byte[] arg2) {} + byte[] arg2) { + } @Override public void onFailure(int arg0, Header[] arg1, - byte[] arg2, Throwable arg3) { + byte[] arg2, Throwable arg3) { AppContext.showToast("网络异常,云端文件暂未删除"); } }); diff --git a/app/src/main/java/net/oschina/app/team/fragment/NoteEditFragment.java b/app/src/main/java/net/oschina/app/team/fragment/NoteEditFragment.java index b25d5e3553a2360eaeacad0171c8e8be057f2490..aec8c0664bf0d4c79cbd3a70c00dccfe999f0c71 100644 --- a/app/src/main/java/net/oschina/app/team/fragment/NoteEditFragment.java +++ b/app/src/main/java/net/oschina/app/team/fragment/NoteEditFragment.java @@ -25,14 +25,14 @@ import net.oschina.app.base.BaseFragment; import net.oschina.app.bean.NotebookData; import net.oschina.app.bean.SimpleBackPage; import net.oschina.app.db.NoteDatabase; +import net.oschina.app.improve.utils.DialogHelper; import net.oschina.app.ui.SimpleBackActivity; -import net.oschina.app.util.DialogHelp; import net.oschina.app.util.KJAnimations; import net.oschina.app.util.StringUtils; import net.oschina.app.util.UIHelper; import butterknife.ButterKnife; -import butterknife.InjectView; +import butterknife.Bind; /** * 便签编辑界面 @@ -41,29 +41,29 @@ import butterknife.InjectView; * */ public class NoteEditFragment extends BaseFragment implements OnTouchListener { - @InjectView(R.id.note_detail_edit) + @Bind(R.id.note_detail_edit) EditText mEtContent; - @InjectView(R.id.note_detail_tv_date) + @Bind(R.id.note_detail_tv_date) TextView mTvDate; - @InjectView(R.id.note_detail_titlebar) + @Bind(R.id.note_detail_titlebar) RelativeLayout mLayoutTitle; - @InjectView(R.id.note_detail_img_thumbtack) + @Bind(R.id.note_detail_img_thumbtack) ImageView mImgThumbtack; - @InjectView(R.id.note_detail_img_button) + @Bind(R.id.note_detail_img_button) ImageView mImgMenu; - @InjectView(R.id.note_detail_menu) + @Bind(R.id.note_detail_menu) RelativeLayout mLayoutMenu; - @InjectView(R.id.note_detail_img_green) + @Bind(R.id.note_detail_img_green) ImageView mImgGreen; - @InjectView(R.id.note_detail_img_blue) + @Bind(R.id.note_detail_img_blue) ImageView mImgBlue; - @InjectView(R.id.note_detail_img_purple) + @Bind(R.id.note_detail_img_purple) ImageView mImgPurple; - @InjectView(R.id.note_detail_img_yellow) + @Bind(R.id.note_detail_img_yellow) ImageView mImgYellow; - @InjectView(R.id.note_detail_img_red) + @Bind(R.id.note_detail_img_red) ImageView mImgRed; private NotebookData editData; @@ -90,9 +90,9 @@ public class NoteEditFragment extends BaseFragment implements OnTouchListener { 0xffddd7d9,// 紫色 }; - public static final int[] sThumbtackImgs = { R.drawable.green, - R.drawable.yellow, R.drawable.red, R.drawable.blue, - R.drawable.purple }; + public static final int[] sThumbtackImgs = { R.mipmap.green, + R.mipmap.yellow, R.mipmap.red, R.mipmap.blue, + R.mipmap.purple }; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, @@ -100,7 +100,7 @@ public class NoteEditFragment extends BaseFragment implements OnTouchListener { super.onCreateView(inflater, container, savedInstanceState); View rootView = inflater.inflate(R.layout.fragment_note_detail, container, false); - ButterKnife.inject(this, rootView); + ButterKnife.bind(this, rootView); initData(); initView(rootView); return rootView; @@ -148,7 +148,7 @@ public class NoteEditFragment extends BaseFragment implements OnTouchListener { noteDb = new NoteDatabase(getActivity()); if (editData == null) { editData = new NotebookData(); - editData.setContent(AppContext.getNoteDraft()); + editData.setContent(""); isNewNote = true; } if (StringUtils.isEmpty(editData.getDate())) { @@ -244,16 +244,16 @@ public class NoteEditFragment extends BaseFragment implements OnTouchListener { if (isNewNote) { final String content = mEtContent.getText().toString(); if (!TextUtils.isEmpty(content)) { - DialogHelp.getConfirmDialog(getActivity(), "是否保存为草稿?", new OnClickListener() { + DialogHelper.getConfirmDialog(getActivity(), "是否保存为草稿?", new OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { - AppContext.setNoteDraft(""); + //AppContext.setNoteDraft(""); getActivity().finish(); } }, new OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { - AppContext.setNoteDraft(content); + //AppContext.setNoteDraft(content); getActivity().finish(); } }).show(); diff --git a/app/src/main/java/net/oschina/app/team/fragment/TeamBoardFragment.java b/app/src/main/java/net/oschina/app/team/fragment/TeamBoardFragment.java index addf0c4596600688140c614a079f7c6a229f2254..425d28131cfbc30ff4009006127deb014653f83f 100644 --- a/app/src/main/java/net/oschina/app/team/fragment/TeamBoardFragment.java +++ b/app/src/main/java/net/oschina/app/team/fragment/TeamBoardFragment.java @@ -8,11 +8,11 @@ import android.widget.TextView; import com.loopj.android.http.AsyncHttpResponseHandler; -import net.oschina.app.AppContext; import net.oschina.app.R; import net.oschina.app.api.remote.OSChinaApi; import net.oschina.app.base.BaseFragment; import net.oschina.app.bean.SimpleBackPage; +import net.oschina.app.improve.account.AccountHelper; import net.oschina.app.team.bean.MyIssueState; import net.oschina.app.team.bean.Team; import net.oschina.app.team.ui.TeamMainActivity; @@ -21,48 +21,46 @@ import net.oschina.app.util.UIHelper; import net.oschina.app.util.XmlUtils; import net.oschina.app.widget.AvatarView; - import org.kymjs.kjframe.utils.SystemTool; import java.io.ByteArrayInputStream; import java.util.Calendar; +import butterknife.Bind; import butterknife.ButterKnife; -import butterknife.InjectView; import butterknife.OnClick; import cz.msebera.android.httpclient.Header; /** * Team面板界面 - * + * * @author kymjs (https://github.com/kymjs) - * */ public class TeamBoardFragment extends BaseFragment { - @InjectView(R.id.team_myissue_waitdo) + @Bind(R.id.team_myissue_waitdo) View mRlWaitDo; - @InjectView(R.id.team_myissue_outdate) + @Bind(R.id.team_myissue_outdate) View mRlWill; - @InjectView(R.id.team_myissue_ing) + @Bind(R.id.team_myissue_ing) View mRlIng; - @InjectView(R.id.team_myissue_all) + @Bind(R.id.team_myissue_all) View mRlAll; - @InjectView(R.id.team_myissue_wait_num) + @Bind(R.id.team_myissue_wait_num) TextView mTvWaitDo; - @InjectView(R.id.team_myissue_outdate_num) + @Bind(R.id.team_myissue_outdate_num) TextView mTvOutdate; - @InjectView(R.id.team_myissue_ing_num) + @Bind(R.id.team_myissue_ing_num) TextView mTvIng; - @InjectView(R.id.team_myissue_all_num) + @Bind(R.id.team_myissue_all_num) TextView mTvAll; - @InjectView(R.id.iv_avatar) + @Bind(R.id.iv_avatar) AvatarView mIvAvatarView; - @InjectView(R.id.team_myissue_name) + @Bind(R.id.team_myissue_name) TextView mTvName; - @InjectView(R.id.team_myissue_date) + @Bind(R.id.team_myissue_date) TextView mTvDate; private Team team; @@ -85,11 +83,11 @@ public class TeamBoardFragment extends BaseFragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { + Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); View rootView = inflater.inflate(R.layout.fragment_team_board, container, false); - ButterKnife.inject(this, rootView); + ButterKnife.bind(this, rootView); initData(); initView(rootView); return rootView; @@ -102,10 +100,9 @@ public class TeamBoardFragment extends BaseFragment { mRlIng.setOnClickListener(this); mRlAll.setOnClickListener(this); - mTvName.setText(AppContext.getInstance().getLoginUser().getName() + "," + mTvName.setText(AccountHelper.getUser().getName() + "," + getGreetings()); - mIvAvatarView.setAvatarUrl(AppContext.getInstance().getLoginUser() - .getPortrait()); + mIvAvatarView.setAvatarUrl(AccountHelper.getUser().getPortrait()); mTvDate.setText("今天是 " + getWeekDay() + "," + SystemTool.getDataTime("yyyy年MM月dd日")); @@ -148,75 +145,75 @@ public class TeamBoardFragment extends BaseFragment { int dayOfWeek = c.get(Calendar.DAY_OF_WEEK); String weekStr = ""; switch (dayOfWeek) { - case 1: - weekStr = "星期日"; - break; - case 2: - weekStr = "星期一"; - break; - case 3: - weekStr = "星期二"; - break; - case 4: - weekStr = "星期三"; - break; - case 5: - weekStr = "星期四"; - break; - case 6: - weekStr = "星期五"; - break; - case 7: - weekStr = "星期六"; - break; + case 1: + weekStr = "星期日"; + break; + case 2: + weekStr = "星期一"; + break; + case 3: + weekStr = "星期二"; + break; + case 4: + weekStr = "星期三"; + break; + case 5: + weekStr = "星期四"; + break; + case 6: + weekStr = "星期五"; + break; + case 7: + weekStr = "星期六"; + break; } return weekStr; } @Override - @OnClick({ R.id.ll_team_active, R.id.ll_team_project, R.id.ll_team_issue, - R.id.ll_team_discuss, R.id.ll_team_diary }) + @OnClick({R.id.ll_team_active, R.id.ll_team_project, R.id.ll_team_issue, + R.id.ll_team_discuss, R.id.ll_team_diary}) public void onClick(View v) { switch (v.getId()) { - case R.id.team_myissue_waitdo: - UIHelper.showSimpleBack(getActivity(), - SimpleBackPage.MY_ISSUE_PAGER, getMyIssueStateBundle(0)); - break; - case R.id.team_myissue_ing: - UIHelper.showSimpleBack(getActivity(), - SimpleBackPage.MY_ISSUE_PAGER, getMyIssueStateBundle(1)); - break; - case R.id.team_myissue_outdate: - UIHelper.showSimpleBack(getActivity(), - SimpleBackPage.MY_ISSUE_PAGER, getMyIssueStateBundle(0)); - break; - case R.id.team_myissue_all: - UIHelper.showSimpleBack(getActivity(), - SimpleBackPage.MY_ISSUE_PAGER, getMyIssueStateBundle(2)); - break; - case R.id.ll_team_active: - UIHelper.showSimpleBack(getActivity(), SimpleBackPage.TEAM_ACTIVE, - getArguments()); - break; - case R.id.ll_team_project: - UIHelper.showSimpleBack(getActivity(), SimpleBackPage.TEAM_PROJECT, - getArguments()); - break; - case R.id.ll_team_issue: - UIHelper.showSimpleBack(getActivity(), SimpleBackPage.TEAM_ISSUE, - getBundle()); - break; - case R.id.ll_team_discuss: - UIHelper.showSimpleBack(getActivity(), SimpleBackPage.TEAM_DISCUSS, - getBundle()); - break; - case R.id.ll_team_diary: - UIHelper.showSimpleBack(getActivity(), SimpleBackPage.TEAM_DIRAY, - getBundle()); - break; - default: - break; + case R.id.team_myissue_waitdo: + UIHelper.showSimpleBack(getActivity(), + SimpleBackPage.MY_ISSUE_PAGER, getMyIssueStateBundle(0)); + break; + case R.id.team_myissue_ing: + UIHelper.showSimpleBack(getActivity(), + SimpleBackPage.MY_ISSUE_PAGER, getMyIssueStateBundle(1)); + break; + case R.id.team_myissue_outdate: + UIHelper.showSimpleBack(getActivity(), + SimpleBackPage.MY_ISSUE_PAGER, getMyIssueStateBundle(0)); + break; + case R.id.team_myissue_all: + UIHelper.showSimpleBack(getActivity(), + SimpleBackPage.MY_ISSUE_PAGER, getMyIssueStateBundle(2)); + break; + case R.id.ll_team_active: + UIHelper.showSimpleBack(getActivity(), SimpleBackPage.TEAM_ACTIVE, + getArguments()); + break; + case R.id.ll_team_project: + UIHelper.showSimpleBack(getActivity(), SimpleBackPage.TEAM_PROJECT, + getArguments()); + break; + case R.id.ll_team_issue: + UIHelper.showSimpleBack(getActivity(), SimpleBackPage.TEAM_ISSUE, + getBundle()); + break; + case R.id.ll_team_discuss: + UIHelper.showSimpleBack(getActivity(), SimpleBackPage.TEAM_DISCUSS, + getBundle()); + break; + case R.id.ll_team_diary: + UIHelper.showSimpleBack(getActivity(), SimpleBackPage.TEAM_DIRAY, + getBundle()); + break; + default: + break; } } @@ -238,8 +235,7 @@ public class TeamBoardFragment extends BaseFragment { } private void requestData() { - OSChinaApi.getMyIssueState(team.getId() + "", AppContext.getInstance() - .getLoginUid() + "", new AsyncHttpResponseHandler() { + OSChinaApi.getMyIssueState(team.getId() + "", AccountHelper.getUserId() + "", new AsyncHttpResponseHandler() { @Override public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { @@ -254,7 +250,8 @@ public class TeamBoardFragment extends BaseFragment { @Override public void onFailure(int arg0, Header[] arg1, byte[] arg2, - Throwable arg3) {} + Throwable arg3) { + } @Override public void onFinish() { diff --git a/app/src/main/java/net/oschina/app/team/fragment/TeamDiaryDetailFragment.java b/app/src/main/java/net/oschina/app/team/fragment/TeamDiaryDetailFragment.java index 550e96c491c072d79ed49e8d3c87428cdce38d4c..40f764c0dd8088101a732738d6015d9ee21ee73b 100644 --- a/app/src/main/java/net/oschina/app/team/fragment/TeamDiaryDetailFragment.java +++ b/app/src/main/java/net/oschina/app/team/fragment/TeamDiaryDetailFragment.java @@ -37,27 +37,27 @@ import net.oschina.app.util.UIHelper; import net.oschina.app.util.XmlUtils; import net.oschina.app.widget.AvatarView; -import cz.msebera.android.httpclient.Header; import java.util.List; +import butterknife.Bind; import butterknife.ButterKnife; -import butterknife.InjectView; +import cz.msebera.android.httpclient.Header; /** * 周报详情
    * 逻辑介绍:用Listview来显示评论内容,在ListView的HeadView中添加本周报的详细内容与周报列表的item。 * 周报的详细内容通过动态添加addView的方式 - * + * * @author kymjs (https://github.com/kymjs) */ public class TeamDiaryDetailFragment extends BaseFragment implements OnSendClickListener { - @InjectView(R.id.listview) + @Bind(R.id.listview) ListView mList; - @InjectView(R.id.swiperefreshlayout) + @Bind(R.id.swiperefreshlayout) SwipeRefreshLayout mSwiperefreshlayout; - @InjectView(R.id.error_layout) + @Bind(R.id.error_layout) EmptyLayout mErrorLayout; private TeamDiary diaryData; @@ -69,12 +69,12 @@ public class TeamDiaryDetailFragment extends BaseFragment implements @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { + Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); View rootView = View.inflate(getActivity(), R.layout.fragment_pull_refresh_listview, null); aty = getActivity(); - ButterKnife.inject(this, rootView); + ButterKnife.bind(this, rootView); initData(); initView(rootView); return rootView; @@ -150,7 +150,7 @@ public class TeamDiaryDetailFragment extends BaseFragment implements /** * 初始化头部周报Title - * + * * @return */ private View initHeaderView() { @@ -168,7 +168,7 @@ public class TeamDiaryDetailFragment extends BaseFragment implements UIHelper.initWebView(content); fillWebViewBody(content); - time.setText(StringUtils.friendly_time(diaryData.getCreateTime())); + time.setText(StringUtils.formatSomeAgo(diaryData.getCreateTime())); return headerView; } @@ -217,7 +217,7 @@ public class TeamDiaryDetailFragment extends BaseFragment implements @Override public void onFailure(int arg0, Header[] arg1, byte[] arg2, - Throwable arg3) { + Throwable arg3) { mErrorLayout.setErrorType(EmptyLayout.NETWORK_ERROR); mErrorLayout.setErrorMessage("网络不好,请稍后重试"); } @@ -236,7 +236,7 @@ public class TeamDiaryDetailFragment extends BaseFragment implements new AsyncHttpResponseHandler() { @Override public void onSuccess(int arg0, Header[] arg1, - final byte[] arg2) { + final byte[] arg2) { List datas = XmlUtils.toBean( TeamRepliesList.class, arg2).getList(); footerView.removeAllViews(); @@ -251,7 +251,7 @@ public class TeamDiaryDetailFragment extends BaseFragment implements name.setText(data.getAuthor().getName()); TextView time = (TextView) layout .findViewById(R.id.tv_time); - time.setText(StringUtils.friendly_time(data + time.setText(StringUtils.formatSomeAgo(data .getCreateTime())); TextView content = (TextView) layout .findViewById(R.id.tv_content); @@ -275,7 +275,8 @@ public class TeamDiaryDetailFragment extends BaseFragment implements @Override public void onFailure(int arg0, Header[] arg1, byte[] arg2, - Throwable arg3) {} + Throwable arg3) { + } @Override public void onFinish() { @@ -287,10 +288,10 @@ public class TeamDiaryDetailFragment extends BaseFragment implements /** * 移除字符串中的Html标签 - * - * @author kymjs (https://github.com/kymjs) + * * @param pHTMLString * @return + * @author kymjs (https://github.com/kymjs) */ public static Spanned stripTags(final String pHTMLString) { String str = pHTMLString.replaceAll("<\\s*>", ""); @@ -303,14 +304,17 @@ public class TeamDiaryDetailFragment extends BaseFragment implements OSChinaTeamApi.pubTeamTweetReply(teamid, 118, diaryData.getId(), str.toString(), new AsyncHttpResponseHandler() { @Override - public void onSuccess(int arg0, Header[] arg1, byte[] arg2) {} + public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { + } @Override public void onFailure(int arg0, Header[] arg1, byte[] arg2, - Throwable arg3) {} - }); + Throwable arg3) { + } + }, getContext()); } @Override - public void onClickFlagButton() {} + public void onClickFlagButton() { + } } diff --git a/app/src/main/java/net/oschina/app/team/fragment/TeamDiscussDetailFragment.java b/app/src/main/java/net/oschina/app/team/fragment/TeamDiscussDetailFragment.java index db03d58efd7b742b1b6bcf0497344211a92bef47..fae51aacb1c84ea41e165a4fb1b441e6736e7255 100644 --- a/app/src/main/java/net/oschina/app/team/fragment/TeamDiscussDetailFragment.java +++ b/app/src/main/java/net/oschina/app/team/fragment/TeamDiscussDetailFragment.java @@ -18,6 +18,7 @@ import net.oschina.app.base.BeseHaveHeaderListFragment; import net.oschina.app.bean.Result; import net.oschina.app.bean.ResultBean; import net.oschina.app.emoji.OnSendClickListener; +import net.oschina.app.improve.account.AccountHelper; import net.oschina.app.team.adapter.TeamReplyAdapter; import net.oschina.app.team.bean.TeamDiscuss; import net.oschina.app.team.bean.TeamDiscussDetail; @@ -29,11 +30,12 @@ import net.oschina.app.util.ThemeSwitchUtils; import net.oschina.app.util.UIHelper; import net.oschina.app.util.XmlUtils; -import cz.msebera.android.httpclient.Header; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.Serializable; +import cz.msebera.android.httpclient.Header; + /** * TeamDiscussDetailFragment.java * @@ -144,7 +146,7 @@ public class TeamDiscussDetailFragment extends // 添加title body.append(String.format("

    %s
    ", detailBean.getTitle())); // 添加作者和时间 - String time = StringUtils.friendly_time(detailBean.getCreateTime()); + String time = StringUtils.formatSomeAgo(detailBean.getCreateTime()); String author = String.format("%s", detailBean.getAuthor().getId(), detailBean.getAuthor().getName()); String answerCountAndVoteup = detailBean.getVoteUp() + "赞/" + detailBean.getAnswerCount() + "回"; @@ -204,11 +206,11 @@ public class TeamDiscussDetailFragment extends AppContext.showToast("请先输入评论内容..."); return; } - if (!AppContext.getInstance().isLogin()) { + if (!AccountHelper.isLogin()) { UIHelper.showLoginActivity(getActivity()); return; } - int uid = AppContext.getInstance().getLoginUid(); + int uid = (int) AccountHelper.getUserId(); OSChinaTeamApi.pubTeamDiscussReply(uid, mTeamId, mDiscussId, str.toString(), mReplyHandler); } diff --git a/app/src/main/java/net/oschina/app/team/fragment/TeamIssueCatalogFragment.java b/app/src/main/java/net/oschina/app/team/fragment/TeamIssueCatalogFragment.java index 19fb2604e539e4533fe04a9fc432e0135d1cd0b1..a001bcb2492cbe00b3b488957bdc1f90eea47917 100644 --- a/app/src/main/java/net/oschina/app/team/fragment/TeamIssueCatalogFragment.java +++ b/app/src/main/java/net/oschina/app/team/fragment/TeamIssueCatalogFragment.java @@ -1,13 +1,13 @@ package net.oschina.app.team.fragment; -import java.io.InputStream; -import java.io.Serializable; +import android.os.Bundle; +import android.view.View; +import android.widget.AdapterView; -import net.oschina.app.AppContext; -import net.oschina.app.R; import net.oschina.app.api.remote.OSChinaTeamApi; import net.oschina.app.base.BaseListFragment; import net.oschina.app.bean.SimpleBackPage; +import net.oschina.app.improve.account.AccountHelper; import net.oschina.app.team.adapter.TeamIssueCatalogAdapter; import net.oschina.app.team.bean.Team; import net.oschina.app.team.bean.TeamIssueCatalog; @@ -16,12 +16,9 @@ import net.oschina.app.team.bean.TeamProject; import net.oschina.app.team.ui.TeamMainActivity; import net.oschina.app.util.UIHelper; import net.oschina.app.util.XmlUtils; -import android.os.Bundle; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.widget.AdapterView; + +import java.io.InputStream; +import java.io.Serializable; /** * 任务分组列表 @@ -69,7 +66,7 @@ public class TeamIssueCatalogFragment extends @Override protected void sendRequestData() { - int uid = AppContext.getInstance().getLoginUid(); + int uid = (int) AccountHelper.getUserId(); int teamId= mTeam.getId(); int projectId = mTeamProject.getGit().getId(); String source = mTeamProject.getSource(); diff --git a/app/src/main/java/net/oschina/app/team/fragment/TeamIssueDetailFragment.java b/app/src/main/java/net/oschina/app/team/fragment/TeamIssueDetailFragment.java index bd32445f858c40b94dd1a2f69ff6f96ba4892319..9def33301b34fe9c70337d30e9569e805e604bb5 100644 --- a/app/src/main/java/net/oschina/app/team/fragment/TeamIssueDetailFragment.java +++ b/app/src/main/java/net/oschina/app/team/fragment/TeamIssueDetailFragment.java @@ -26,6 +26,7 @@ import net.oschina.app.base.BaseFragment; import net.oschina.app.bean.Result; import net.oschina.app.bean.ResultBean; import net.oschina.app.emoji.OnSendClickListener; +import net.oschina.app.improve.utils.DialogHelper; import net.oschina.app.team.bean.Team; import net.oschina.app.team.bean.TeamIssue; import net.oschina.app.team.bean.TeamIssueCatalog; @@ -35,7 +36,6 @@ import net.oschina.app.team.bean.TeamReply; import net.oschina.app.team.bean.TeamReplyBean; import net.oschina.app.ui.DetailActivity; import net.oschina.app.ui.empty.EmptyLayout; -import net.oschina.app.util.DialogHelp; import net.oschina.app.util.HTMLUtil; import net.oschina.app.util.StringUtils; import net.oschina.app.util.TypefaceUtils; @@ -43,12 +43,12 @@ import net.oschina.app.util.ViewUtils; import net.oschina.app.util.XmlUtils; import net.oschina.app.widget.AvatarView; -import cz.msebera.android.httpclient.Header; import java.util.List; +import butterknife.Bind; import butterknife.ButterKnife; -import butterknife.InjectView; import butterknife.OnClick; +import cz.msebera.android.httpclient.Header; /** * TeamIssueDetailFragmentNew.java @@ -65,34 +65,34 @@ public class TeamIssueDetailFragment extends BaseFragment implements private TeamIssueCatalog mCatalog; - @InjectView(R.id.content) + @Bind(R.id.content) View mContent; - @InjectView(R.id.error_layout) + @Bind(R.id.error_layout) EmptyLayout mErrorLayout; - @InjectView(R.id.ll_issue_project) + @Bind(R.id.ll_issue_project) View mProjectView; - @InjectView(R.id.tv_issue_project) + @Bind(R.id.tv_issue_project) TextView mTvProject; - @InjectView(R.id.tv_issue_state_title) + @Bind(R.id.tv_issue_state_title) TextView mTvStateTitle; - @InjectView(R.id.tv_issue_title) + @Bind(R.id.tv_issue_title) TextView mTvTitle; - @InjectView(R.id.tv_issue_touser) + @Bind(R.id.tv_issue_touser) TextView mTvToUser; - @InjectView(R.id.tv_issue_cooperate_user) + @Bind(R.id.tv_issue_cooperate_user) TextView mTvCooperateUser; - @InjectView(R.id.tv_issue_die_time) + @Bind(R.id.tv_issue_die_time) TextView mTvDieTime; - @InjectView(R.id.tv_issue_state) + @Bind(R.id.tv_issue_state) TextView mTvState; - @InjectView(R.id.ll_issue_labels) + @Bind(R.id.ll_issue_labels) LinearLayout mLLlabels; - @InjectView(R.id.tv_issue_attachments) + @Bind(R.id.tv_issue_attachments) TextView mTvAttachments; - @InjectView(R.id.tv_issue_relations) + @Bind(R.id.tv_issue_relations) TextView mTvRelations; - @InjectView(R.id.tv_issue_child) + @Bind(R.id.tv_issue_child) TextView mTvIssueChild; @Override @@ -120,7 +120,7 @@ public class TeamIssueDetailFragment extends BaseFragment implements @Override public void initView(View view) { - ButterKnife.inject(this, view); + ButterKnife.bind(this, view); TypefaceUtils.setTypeface((TextView) view .findViewById(R.id.tv_issue_fa_touser)); @@ -376,7 +376,7 @@ public class TeamIssueDetailFragment extends BaseFragment implements // bundle.putSerializable(TeamMainActivity.BUNDLE_KEY_TEAM, mTeam); // bundle.putSerializable(TeamMainActivity.BUNDLE_KEY_PROJECT, // mTeamIssue.getProject()); - // UIHelper.showSimpleBack(getActivity(), + // UIUtil.showSimpleBack(getActivity(), // SimpleBackPage.TEAM_PROJECT_MEMBER_SELECT, bundle); break; case R.id.ll_issue_cooperate_user: @@ -417,22 +417,23 @@ public class TeamIssueDetailFragment extends BaseFragment implements } } final int selIndex = index; - dialog = DialogHelp.getSingleChoiceDialog(getActivity(), "更改任务状态", items, selIndex, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (i == selIndex) { - dialog.dismiss(); - return; - } - mTeamIssue.setState(itemsEn[i].toString()); - OSChinaTeamApi.changeIssueState(mTeam.getId(), mTeamIssue, - "state", mChangeIssueHandler); - dialog.dismiss(); - } - }).show(); + dialog = DialogHelper.getSingleChoiceDialog(getActivity(), "更改任务状态", items, selIndex, new + DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + if (i == selIndex) { + dialog.dismiss(); + return; + } + mTeamIssue.setState(itemsEn[i].toString()); + OSChinaTeamApi.changeIssueState(mTeam.getId(), mTeamIssue, + "state", mChangeIssueHandler, getContext()); + dialog.dismiss(); + } + }).show(); } - @InjectView(R.id.ll_issue_childs) + @Bind(R.id.ll_issue_childs) LinearLayout mLLChildIssues; private void setChildIssues(List list) { @@ -514,7 +515,7 @@ public class TeamIssueDetailFragment extends BaseFragment implements super.onFinish(); hideWaitDialog(); } - }); + }, getContext()); } private void switchChildIssueState(TeamIssue childIssue) { @@ -525,7 +526,7 @@ public class TeamIssueDetailFragment extends BaseFragment implements } } - @InjectView(R.id.ll_issue_comments) + @Bind(R.id.ll_issue_comments) LinearLayout mLLComments; // 请求任务的评论 @@ -570,7 +571,7 @@ public class TeamIssueDetailFragment extends BaseFragment implements TextView content = (TextView) cell.findViewById(R.id.tv_content); content.setText(HTMLUtil.delHTMLTag(reply.getContent())); TextView time = (TextView) cell.findViewById(R.id.tv_time); - time.setText(StringUtils.friendly_time(reply.getCreateTime())); + time.setText(StringUtils.formatSomeAgo(reply.getCreateTime())); mLLComments.addView(cell); } @@ -606,7 +607,7 @@ public class TeamIssueDetailFragment extends BaseFragment implements super.onFinish(); hideWaitDialog(); } - }); + }, getContext()); } @Override diff --git a/app/src/main/java/net/oschina/app/team/fragment/TeamIssueFragment.java b/app/src/main/java/net/oschina/app/team/fragment/TeamIssueFragment.java index 43ac27d553f950e7684a9084a1064b8ea4f9b4cb..2c7f698604d43c91c980623654b739daebd575e3 100755 --- a/app/src/main/java/net/oschina/app/team/fragment/TeamIssueFragment.java +++ b/app/src/main/java/net/oschina/app/team/fragment/TeamIssueFragment.java @@ -16,6 +16,7 @@ import net.oschina.app.api.remote.OSChinaTeamApi; import net.oschina.app.base.BaseActivity; import net.oschina.app.base.BaseListFragment; import net.oschina.app.bean.ListEntity; +import net.oschina.app.improve.utils.DialogHelper; import net.oschina.app.team.adapter.TeamIssueAdapter; import net.oschina.app.team.bean.Team; import net.oschina.app.team.bean.TeamIssue; @@ -24,7 +25,6 @@ import net.oschina.app.team.bean.TeamIssueList; import net.oschina.app.team.bean.TeamProject; import net.oschina.app.team.ui.TeamMainActivity; import net.oschina.app.ui.empty.EmptyLayout; -import net.oschina.app.util.DialogHelp; import net.oschina.app.util.StringUtils; import net.oschina.app.util.UIHelper; import net.oschina.app.util.XmlUtils; @@ -142,7 +142,7 @@ public class TeamIssueFragment extends BaseListFragment { } } - dialog = DialogHelp.getSingleChoiceDialog(getActivity(), "选择任务状态", items, index, new DialogInterface.OnClickListener() { + dialog = DialogHelper.getSingleChoiceDialog(getActivity(), "选择任务状态", items, index, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { issueState = (itemsEn[i]).toString(); @@ -192,7 +192,7 @@ public class TeamIssueFragment extends BaseListFragment { private void setNoTeamIssue() { mErrorLayout.setErrorType(EmptyLayout.NODATA); - mErrorLayout.setErrorImag(R.drawable.page_icon_empty); + mErrorLayout.setErrorImag(R.mipmap.page_icon_empty); String msg = getResources().getString(R.string.team_empty_issue); mErrorLayout.setErrorMessage(msg); } diff --git a/app/src/main/java/net/oschina/app/team/fragment/TeamMemberFragment.java b/app/src/main/java/net/oschina/app/team/fragment/TeamMemberFragment.java index 1e0ac5c7ce3a48a35afdcced4db519122187f8ea..85b33f06b309f5e10576aabe16f5515bb6a3f537 100644 --- a/app/src/main/java/net/oschina/app/team/fragment/TeamMemberFragment.java +++ b/app/src/main/java/net/oschina/app/team/fragment/TeamMemberFragment.java @@ -1,6 +1,17 @@ package net.oschina.app.team.fragment; -import java.util.List; +import android.app.Activity; +import android.os.Bundle; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.GridView; + +import com.loopj.android.http.AsyncHttpResponseHandler; import net.oschina.app.AppContext; import net.oschina.app.R; @@ -16,23 +27,13 @@ import net.oschina.app.ui.empty.EmptyLayout; import net.oschina.app.util.UIHelper; import net.oschina.app.util.XmlUtils; -import cz.msebera.android.httpclient.Header; import org.kymjs.kjframe.http.KJAsyncTask; -import android.app.Activity; -import android.os.Bundle; -import android.support.v4.widget.SwipeRefreshLayout; -import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.GridView; -import butterknife.ButterKnife; -import butterknife.InjectView; +import java.util.List; -import com.loopj.android.http.AsyncHttpResponseHandler; +import butterknife.Bind; +import butterknife.ButterKnife; +import cz.msebera.android.httpclient.Header; /** * 团队成员界面 @@ -42,11 +43,11 @@ import com.loopj.android.http.AsyncHttpResponseHandler; */ public class TeamMemberFragment extends BaseFragment { - @InjectView(R.id.fragment_team_grid) + @Bind(R.id.fragment_team_grid) GridView mGrid; - @InjectView(R.id.fragment_team_empty) + @Bind(R.id.fragment_team_empty) EmptyLayout mEmpty; - @InjectView(R.id.swiperefreshlayout) + @Bind(R.id.swiperefreshlayout) SwipeRefreshLayout mSwipeRefreshLayout; private Activity aty; @@ -79,7 +80,7 @@ public class TeamMemberFragment extends BaseFragment { View rootView = inflater.inflate(R.layout.fragment_team_member, container, false); aty = getActivity(); - ButterKnife.inject(this, rootView); + ButterKnife.bind(this, rootView); TeamMemberList list = (TeamMemberList) CacheManager.readObject(aty, TEAM_MEMBER_DATA); diff --git a/app/src/main/java/net/oschina/app/team/fragment/TeamMemberInformationFragment.java b/app/src/main/java/net/oschina/app/team/fragment/TeamMemberInformationFragment.java index 556b2cf552407d289ff9edbfd7f06db8b172f810..a9f468c3ce66424bc98262cd00e5ab3758cc25d4 100644 --- a/app/src/main/java/net/oschina/app/team/fragment/TeamMemberInformationFragment.java +++ b/app/src/main/java/net/oschina/app/team/fragment/TeamMemberInformationFragment.java @@ -135,17 +135,6 @@ public class TeamMemberInformationFragment extends BaseListFragment if (obj instanceof TeamActive) { data = (TeamActive) obj; } - Intent intent = new Intent(aty, DetailActivity.class); - Bundle bundle = new Bundle(); - bundle.putSerializable( - TeamActiveFragment.DYNAMIC_FRAGMENT_KEY, data); - bundle.putInt( - TeamActiveFragment.DYNAMIC_FRAGMENT_TEAM_KEY, - teamId); - bundle.putInt(DetailActivity.BUNDLE_KEY_DISPLAY_TYPE, - DetailActivity.DISPLAY_TEAM_TWEET_DETAIL); - intent.putExtras(bundle); - aty.startActivity(intent); } } } diff --git a/app/src/main/java/net/oschina/app/team/fragment/TeamProjectActiveFragment.java b/app/src/main/java/net/oschina/app/team/fragment/TeamProjectActiveFragment.java index d68b44d9f1f8432984311cfa00556cd0ece61fc4..9dcc0671cdb89a114a8e7dc8f4f4f494b4829479 100644 --- a/app/src/main/java/net/oschina/app/team/fragment/TeamProjectActiveFragment.java +++ b/app/src/main/java/net/oschina/app/team/fragment/TeamProjectActiveFragment.java @@ -101,7 +101,7 @@ public class TeamProjectActiveFragment extends BaseListFragment { private void setNoProjectActive() { mErrorLayout.setErrorType(EmptyLayout.NODATA); - mErrorLayout.setErrorImag(R.drawable.page_icon_empty); + mErrorLayout.setErrorImag(R.mipmap.page_icon_empty); String str = getResources().getString( R.string.team_empty_project_active); mErrorLayout.setErrorMessage(str); diff --git a/app/src/main/java/net/oschina/app/team/fragment/TeamProjectFragment.java b/app/src/main/java/net/oschina/app/team/fragment/TeamProjectFragment.java index 6b24f7af83883b3a3d06a89898177d0534969f82..63095edb08bcda05802360ab49fcc73310800fbc 100644 --- a/app/src/main/java/net/oschina/app/team/fragment/TeamProjectFragment.java +++ b/app/src/main/java/net/oschina/app/team/fragment/TeamProjectFragment.java @@ -94,7 +94,7 @@ public class TeamProjectFragment extends BaseListFragment { private void setNoProject() { mErrorLayout.setErrorType(EmptyLayout.NODATA); - mErrorLayout.setErrorImag(R.drawable.page_icon_empty); + mErrorLayout.setErrorImag(R.mipmap.page_icon_empty); String str = getResources().getString(R.string.team_empty_project); mErrorLayout.setErrorMessage(str); } diff --git a/app/src/main/java/net/oschina/app/team/fragment/TeamProjectMemberFragment.java b/app/src/main/java/net/oschina/app/team/fragment/TeamProjectMemberFragment.java index ddc6c0c2a30dd17a0cf239da08479f2f58081216..580996a45b1c47f53c02e03bcc718e0a1d8fbd06 100644 --- a/app/src/main/java/net/oschina/app/team/fragment/TeamProjectMemberFragment.java +++ b/app/src/main/java/net/oschina/app/team/fragment/TeamProjectMemberFragment.java @@ -1,8 +1,8 @@ package net.oschina.app.team.fragment; -import java.io.InputStream; -import java.io.Serializable; -import java.util.List; +import android.os.Bundle; +import android.view.View; +import android.widget.AdapterView; import net.oschina.app.R; import net.oschina.app.api.remote.OSChinaTeamApi; @@ -17,19 +17,19 @@ import net.oschina.app.team.ui.TeamMainActivity; import net.oschina.app.ui.empty.EmptyLayout; import net.oschina.app.util.UIHelper; import net.oschina.app.util.XmlUtils; -import android.os.Bundle; -import android.view.View; -import android.widget.AdapterView; + +import java.io.InputStream; +import java.io.Serializable; +import java.util.List; /** * TeamProjectFragment.java - * + * * @author 火蚁(http://my.oschina.net/u/253900) - * * @data 2015-2-28 下午4:08:58 */ public class TeamProjectMemberFragment extends - BaseListFragment { + BaseListFragment { private Team mTeam; @@ -39,73 +39,73 @@ public class TeamProjectMemberFragment extends @Override public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - Bundle bundle = getArguments(); - if (bundle != null) { - mTeam = (Team) bundle - .getSerializable(TeamMainActivity.BUNDLE_KEY_TEAM); - - mTeamProject = (TeamProject) bundle.getSerializable(TeamMainActivity.BUNDLE_KEY_PROJECT); - - mTeamId = mTeam.getId(); - } + super.onCreate(savedInstanceState); + Bundle bundle = getArguments(); + if (bundle != null) { + mTeam = (Team) bundle + .getSerializable(TeamMainActivity.BUNDLE_KEY_TEAM); + + mTeamProject = (TeamProject) bundle.getSerializable(TeamMainActivity.BUNDLE_KEY_PROJECT); + + mTeamId = mTeam.getId(); + } } @Override protected TeamProjectMemberAdapter getListAdapter() { - // TODO Auto-generated method stub - return new TeamProjectMemberAdapter(); + // TODO Auto-generated method stub + return new TeamProjectMemberAdapter(); } @Override protected String getCacheKeyPrefix() { - return "team_project_member_list_" + mTeamId + "_" + mTeamProject.getGit().getId(); + return "team_project_member_list_" + mTeamId + "_" + mTeamProject.getGit().getId(); } @Override protected TeamMemberList parseList(InputStream is) throws Exception { - TeamMemberList list = XmlUtils.toBean( - TeamMemberList.class, is); - return list; + TeamMemberList list = XmlUtils.toBean( + TeamMemberList.class, is); + return list; } @Override protected TeamMemberList readList(Serializable seri) { - return ((TeamMemberList) seri); + return ((TeamMemberList) seri); } @Override protected void sendRequestData() { - // TODO Auto-generated method stub - OSChinaTeamApi.getTeamProjectMemberList(mTeamId, mTeamProject, - mHandler); + // TODO Auto-generated method stub + OSChinaTeamApi.getTeamProjectMemberList(mTeamId, mTeamProject, + mHandler, getContext()); } @Override protected void executeOnLoadDataSuccess(List data) { - // TODO Auto-generated method stub - super.executeOnLoadDataSuccess(data); - if (mAdapter.getData().isEmpty()) { - setNoProjectMember(); - } - mAdapter.setState(ListBaseAdapter.STATE_NO_MORE); + // TODO Auto-generated method stub + super.executeOnLoadDataSuccess(data); + if (mAdapter.getData().isEmpty()) { + setNoProjectMember(); + } + mAdapter.setState(ListBaseAdapter.STATE_NO_MORE); } private void setNoProjectMember() { - mErrorLayout.setErrorType(EmptyLayout.NODATA); - mErrorLayout.setErrorImag(R.drawable.page_icon_empty); - String str = getResources().getString( - R.string.team_empty_project_member); - mErrorLayout.setErrorMessage(str); + mErrorLayout.setErrorType(EmptyLayout.NODATA); + mErrorLayout.setErrorImag(R.mipmap.page_icon_empty); + String str = getResources().getString( + R.string.team_empty_project_member); + mErrorLayout.setErrorMessage(str); } - + @Override public void onItemClick(AdapterView parent, View view, int position, - long id) { + long id) { // TODO Auto-generated method stub - TeamMember teamMember = mAdapter.getItem(position); - if (teamMember != null) { - UIHelper.showTeamMemberInfo(getActivity(), mTeamId, teamMember); - } + TeamMember teamMember = mAdapter.getItem(position); + if (teamMember != null) { + UIHelper.showTeamMemberInfo(getActivity(), mTeamId, teamMember); + } } } diff --git a/app/src/main/java/net/oschina/app/team/fragment/TeamTweetDetailFragment.java b/app/src/main/java/net/oschina/app/team/fragment/TeamTweetDetailFragment.java index db95138994e65340df72af8b1f6d4aa39567847c..cfada60220f4ce48d4635cfe09aa1bce015ac77d 100644 --- a/app/src/main/java/net/oschina/app/team/fragment/TeamTweetDetailFragment.java +++ b/app/src/main/java/net/oschina/app/team/fragment/TeamTweetDetailFragment.java @@ -29,16 +29,17 @@ import net.oschina.app.bean.ListEntity; import net.oschina.app.bean.Result; import net.oschina.app.bean.ResultBean; import net.oschina.app.emoji.OnSendClickListener; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.utils.DialogHelper; import net.oschina.app.team.adapter.TeamReplyAdapter; import net.oschina.app.team.bean.TeamActive; import net.oschina.app.team.bean.TeamActiveDetail; import net.oschina.app.team.bean.TeamRepliesList; import net.oschina.app.team.bean.TeamReply; import net.oschina.app.ui.DetailActivity; -import net.oschina.app.ui.ImagePreviewActivity; +import net.oschina.app.ui.OSCPhotosActivity; import net.oschina.app.ui.empty.EmptyLayout; import net.oschina.app.util.BitmapHelper; -import net.oschina.app.util.DialogHelp; import net.oschina.app.util.HTMLUtil; import net.oschina.app.util.StringUtils; import net.oschina.app.util.TDevice; @@ -119,7 +120,7 @@ public class TeamTweetDetailFragment extends img_head.setAvatarUrl(active.getAuthor().getPortrait()); tv_name.setText(active.getAuthor().getName()); - tv_date.setText(StringUtils.friendly_time(active.getCreateTime())); + tv_date.setText(StringUtils.formatSomeAgo(active.getCreateTime())); tv_client.setText("Android"); tv_client.setVisibility(View.GONE); String imgPath = active.getBody().getImage(); @@ -139,12 +140,12 @@ public class TeamTweetDetailFragment extends */ private void handleComment(String text) { showWaitDialog(R.string.progress_submit); - if (!AppContext.getInstance().isLogin()) { + if (!AccountHelper.isLogin()) { UIHelper.showLoginActivity(getActivity()); return; } OSChinaTeamApi.pubTeamTweetReply(teamId, active.getType(), - active.getId(), text, mCommentHandler); + active.getId(), text, mCommentHandler, getContext()); } private void initImageSize(Context cxt) { @@ -186,8 +187,7 @@ public class TeamTweetDetailFragment extends pic.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - ImagePreviewActivity.showImagePrivew(aty, 0, - new String[]{realUrl}); + OSCPhotosActivity.showImagePreview(aty, realUrl); } }); } @@ -196,8 +196,7 @@ public class TeamTweetDetailFragment extends @Override protected void requestDetailData(boolean isRefresh) { - OSChinaApi.getDynamicDetail(active.getId(), teamId, AppContext - .getInstance().getLoginUid(), mDetailHandler); + OSChinaApi.getDynamicDetail(active.getId(), teamId, (int) AccountHelper.getUserId(), mDetailHandler); } @Override @@ -258,14 +257,13 @@ public class TeamTweetDetailFragment extends final TeamReply item = mAdapter.getItem(position - 1); if (item == null) return false; - int itemsLen = item.getAuthor().getId() == AppContext.getInstance() - .getLoginUid() ? 2 : 1; + int itemsLen = item.getAuthor().getId() == AccountHelper.getUserId() ? 2 : 1; String[] items = new String[itemsLen]; items[0] = getResources().getString(R.string.copy); if (itemsLen == 2) { items[1] = getResources().getString(R.string.delete); } - DialogHelp.getSelectDialog(getActivity(), items, new DialogInterface.OnClickListener() { + DialogHelper.getSelectDialog(getActivity(), items, "取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { if (i == 0) { @@ -281,7 +279,7 @@ public class TeamTweetDetailFragment extends } private void handleDeleteComment(TeamReply comment) { - if (!AppContext.getInstance().isLogin()) { + if (!AccountHelper.isLogin()) { UIHelper.showLoginActivity(getActivity()); return; } @@ -381,7 +379,7 @@ public class TeamTweetDetailFragment extends AppContext.showToastShort(R.string.tip_network_error); return; } - if (!AppContext.getInstance().isLogin()) { + if (!AccountHelper.isLogin()) { UIHelper.showLoginActivity(getActivity()); return; } diff --git a/app/src/main/java/net/oschina/app/team/ui/TeamMainActivity.java b/app/src/main/java/net/oschina/app/team/ui/TeamMainActivity.java index ac9cd40ca8950a105971cc603a33f28c5b98ebd5..ccc159e0dfafdfb299389fb0617d1d580b660bdc 100644 --- a/app/src/main/java/net/oschina/app/team/ui/TeamMainActivity.java +++ b/app/src/main/java/net/oschina/app/team/ui/TeamMainActivity.java @@ -19,21 +19,22 @@ import net.oschina.app.AppContext; import net.oschina.app.R; import net.oschina.app.api.remote.OSChinaApi; import net.oschina.app.base.BaseActivity; +import net.oschina.app.improve.account.AccountHelper; import net.oschina.app.team.bean.Team; import net.oschina.app.team.bean.TeamList; import net.oschina.app.team.viewpagefragment.TeamMainViewPagerFragment; import net.oschina.app.ui.empty.EmptyLayout; import net.oschina.app.util.XmlUtils; -import cz.msebera.android.httpclient.Header; import org.kymjs.kjframe.utils.PreferenceHelper; import org.kymjs.kjframe.utils.StringUtils; import java.util.ArrayList; import java.util.List; +import butterknife.Bind; import butterknife.ButterKnife; -import butterknife.InjectView; +import cz.msebera.android.httpclient.Header; /** * 团队主界面 @@ -45,8 +46,7 @@ import butterknife.InjectView; public class TeamMainActivity extends BaseActivity implements ActionBar.OnNavigationListener { private final String TEAM_LIST_FILE = "team_list_file"; - private final String TEAM_LIST_KEY = "team_list_key" - + AppContext.getInstance().getLoginUid(); + private String TEAM_LIST_KEY = null; public final static String BUNDLE_KEY_TEAM = "bundle_key_team"; @@ -54,15 +54,13 @@ public class TeamMainActivity extends BaseActivity implements ActionBar.OnNaviga public final static String BUNDLE_KEY_ISSUE_CATALOG = "bundle_key_catalog_list"; - private final String tag = "team_view"; - private FragmentManager mFragmentManager; private int mCurrentContentIndex = -1; - @InjectView(R.id.error_layout) + @Bind(R.id.error_layout) EmptyLayout mErrorLayout; - @InjectView(R.id.main_content) + @Bind(R.id.main_content) View container; @Override @@ -81,7 +79,9 @@ public class TeamMainActivity extends BaseActivity implements ActionBar.OnNaviga @Override public void initView() { - ButterKnife.inject(this); + + TEAM_LIST_KEY = "team_list_key" + AccountHelper.getUserId(); + ButterKnife.bind(this); // 隐藏actionbar的标题 mActionBar.setDisplayShowTitleEnabled(false); mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING); @@ -114,19 +114,15 @@ public class TeamMainActivity extends BaseActivity implements ActionBar.OnNaviga private final List teamName = new ArrayList(); private List teamDatas = new ArrayList(); - /** - * @param pos - */ private void switchTeam(int pos) { if (pos == mCurrentContentIndex) return; showWaitDialog("正在切换..."); FragmentTransaction ft = mFragmentManager.beginTransaction(); - if (tag != null) { - Fragment fragment = mFragmentManager.findFragmentByTag(tag); - if (fragment != null) { - ft.remove(fragment); - } + String tag = "team_view"; + Fragment fragmentf = mFragmentManager.findFragmentByTag(tag); + if (fragmentf != null) { + ft.remove(fragmentf); } try { TeamMainViewPagerFragment fragment = TeamMainViewPagerFragment.class @@ -155,8 +151,6 @@ public class TeamMainActivity extends BaseActivity implements ActionBar.OnNaviga // mErrorLayout.setErrorType(EmptyLayout.HIDE_LAYOUT); teamDatas = TeamList.toTeamList(cache); setTeamDataState(); - } else { - //mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING); } OSChinaApi.teamList(new AsyncHttpResponseHandler() { @@ -186,7 +180,7 @@ public class TeamMainActivity extends BaseActivity implements ActionBar.OnNaviga Throwable arg3) { //AppContext.showToast("网络不好,请稍后重试"); } - }); + }, this); } private void setTeamDataState() { @@ -197,7 +191,7 @@ public class TeamMainActivity extends BaseActivity implements ActionBar.OnNaviga mErrorLayout.setErrorType(EmptyLayout.NODATA); String msg = getResources().getString(R.string.team_empty); mErrorLayout.setErrorMessage(msg); - mErrorLayout.setErrorImag(R.drawable.page_icon_empty); + mErrorLayout.setErrorImag(R.mipmap.page_icon_empty); } else { mErrorLayout.setErrorType(EmptyLayout.HIDE_LAYOUT); container.setVisibility(View.VISIBLE); @@ -240,8 +234,7 @@ public class TeamMainActivity extends BaseActivity implements ActionBar.OnNaviga public View getView(int position, View convertView, ViewGroup parent) { // TODO Auto-generated method stub if (convertView == null) { - convertView = LayoutInflater.from(context).inflate( - R.layout.spinner_layout_head, null); + convertView = View.inflate(context, R.layout.spinner_layout_head, null); } ((TextView) convertView).setText(getItem(position)); @@ -271,25 +264,21 @@ public class TeamMainActivity extends BaseActivity implements ActionBar.OnNaviga @Override public int getCount() { - // TODO Auto-generated method stub return teams.size(); } @Override public void notifyDataSetChanged() { - // TODO Auto-generated method stub super.notifyDataSetChanged(); } @Override public String getItem(int position) { - // TODO Auto-generated method stub return teams.get(position); } @Override public long getItemId(int position) { - // TODO Auto-generated method stub return position; } diff --git a/app/src/main/java/net/oschina/app/team/ui/TeamNewActiveActivity.java b/app/src/main/java/net/oschina/app/team/ui/TeamNewActiveActivity.java index 862cfbee4f614ffaa434790deea48e828209f10a..e59b0ffcd87872e4719d5d1646c4e846f10f7608 100644 --- a/app/src/main/java/net/oschina/app/team/ui/TeamNewActiveActivity.java +++ b/app/src/main/java/net/oschina/app/team/ui/TeamNewActiveActivity.java @@ -37,31 +37,30 @@ import net.oschina.app.emoji.EmojiKeyboardFragment; import net.oschina.app.emoji.Emojicon; import net.oschina.app.emoji.InputHelper; import net.oschina.app.emoji.OnEmojiClickListener; +import net.oschina.app.improve.utils.DialogHelper; import net.oschina.app.team.bean.Team; import net.oschina.app.team.bean.TeamMember; import net.oschina.app.team.bean.TeamMemberList; -import net.oschina.app.util.DialogHelp; import net.oschina.app.util.FileUtil; import net.oschina.app.util.ImageUtils; import net.oschina.app.util.StringUtils; import net.oschina.app.util.XmlUtils; -import cz.msebera.android.httpclient.Header; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; +import butterknife.Bind; import butterknife.ButterKnife; -import butterknife.InjectView; import butterknife.OnClick; +import cz.msebera.android.httpclient.Header; /** * 团队新动态 TeamNewActiveFragment.java - * + * * @author 火蚁(http://my.oschina.net/u/253900) - * * @data 2015-3-6 下午6:39:53 */ public class TeamNewActiveActivity extends BaseActivity { @@ -73,28 +72,28 @@ public class TeamNewActiveActivity extends BaseActivity { private MenuItem mMenuSend; - @InjectView(R.id.ib_emoji_keyboard) + @Bind(R.id.ib_emoji_keyboard) ImageButton mIbEmoji; - @InjectView(R.id.ib_picture) + @Bind(R.id.ib_picture) ImageButton mIbPicture; - @InjectView(R.id.ib_mention) + @Bind(R.id.ib_mention) ImageButton mIbMention; - @InjectView(R.id.ib_trend_software) + @Bind(R.id.ib_trend_software) ImageButton mIbTrendSoftware; - @InjectView(R.id.tv_clear) + @Bind(R.id.tv_clear) TextView mTvClear; - @InjectView(R.id.rl_img) + @Bind(R.id.rl_img) View mLyImage; - @InjectView(R.id.iv_img) + @Bind(R.id.iv_img) ImageView mIvImage; - @InjectView(R.id.et_content) + @Bind(R.id.et_content) EditText mEtInput; private final EmojiKeyboardFragment keyboardFragment = new EmojiKeyboardFragment(); @@ -126,38 +125,38 @@ public class TeamNewActiveActivity extends BaseActivity { } @Override - @OnClick({ R.id.ib_picture, R.id.ib_mention, R.id.ib_trend_software, - R.id.ib_emoji_keyboard, R.id.iv_clear_img, R.id.tv_clear }) + @OnClick({R.id.ib_picture, R.id.ib_mention, R.id.ib_trend_software, + R.id.ib_emoji_keyboard, R.id.iv_clear_img, R.id.tv_clear}) public void onClick(View v) { switch (v.getId()) { - case R.id.ib_emoji_keyboard: - if (keyboardFragment.isShow()) { - keyboardFragment.hideEmojiKeyBoard(); - keyboardFragment.showSoftKeyboard(mEtInput); - } else { - keyboardFragment.showEmojiKeyBoard(); - keyboardFragment.hideSoftKeyboard(); - } - break; - case R.id.ib_picture: - handleSelectPicture(); - break; - case R.id.ib_mention: - tryToShowMetionUser(); - break; - case R.id.ib_trend_software: - insertTrendSoftware(); - break; - case R.id.iv_clear_img: - mIvImage.setImageBitmap(null); - mLyImage.setVisibility(View.GONE); - imgFile = null; - break; - case R.id.tv_clear: - handleClearWords(); - break; - default: - break; + case R.id.ib_emoji_keyboard: + if (keyboardFragment.isShow()) { + keyboardFragment.hideEmojiKeyBoard(); + keyboardFragment.showSoftKeyboard(mEtInput); + } else { + keyboardFragment.showEmojiKeyBoard(); + keyboardFragment.hideSoftKeyboard(); + } + break; + case R.id.ib_picture: + handleSelectPicture(); + break; + case R.id.ib_mention: + tryToShowMetionUser(); + break; + case R.id.ib_trend_software: + insertTrendSoftware(); + break; + case R.id.iv_clear_img: + mIvImage.setImageBitmap(null); + mLyImage.setVisibility(View.GONE); + imgFile = null; + break; + case R.id.tv_clear: + handleClearWords(); + break; + default: + break; } } @@ -165,7 +164,7 @@ public class TeamNewActiveActivity extends BaseActivity { private void handleClearWords() { if (TextUtils.isEmpty(mEtInput.getText().toString())) return; - DialogHelp.getConfirmDialog(this, "是否清空内容?", new OnClickListener() { + DialogHelper.getConfirmDialog(this, "是否清空内容?", new OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { mEtInput.getText().clear(); @@ -202,23 +201,17 @@ public class TeamNewActiveActivity extends BaseActivity { @Override public void initView() { // TODO Auto-generated method stub - ButterKnife.inject(this); + ButterKnife.bind(this); setActionBarTitle(R.string.team_new_active); mTvClear.setText(String.valueOf(MAX_TEXT_LENGTH)); mEtInput.addTextChangedListener(new TextWatcher() { @Override - public void onTextChanged(CharSequence s, int start, int before, - int count) { - // TODO Auto-generated method stub - + public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override - public void beforeTextChanged(CharSequence s, int start, int count, - int after) { - // TODO Auto-generated method stub - + public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override @@ -254,23 +247,21 @@ public class TeamNewActiveActivity extends BaseActivity { private void updateSendMenu() { if (mEtInput.getText().length() == 0) { mMenuSend.setEnabled(false); - mMenuSend.setIcon(R.drawable.actionbar_unsend_icon); + mMenuSend.setIcon(R.mipmap.actionbar_unsend_icon); } else { mMenuSend.setEnabled(true); - mMenuSend.setIcon(R.drawable.actionbar_send_icon); + mMenuSend.setIcon(R.mipmap.actionbar_send_icon); } } @Override public void initData() { - // TODO Auto-generated method stub mTeam = (Team) getIntent().getExtras().getSerializable( TeamMainActivity.BUNDLE_KEY_TEAM); } @Override public boolean onCreateOptionsMenu(Menu menu) { - // TODO Auto-generated method stub getMenuInflater().inflate(R.menu.pub_new_team_active_menu, menu); mMenuSend = menu.findItem(R.id.public_menu_send); updateSendMenu(); @@ -279,14 +270,10 @@ public class TeamNewActiveActivity extends BaseActivity { @Override public boolean onOptionsItemSelected(MenuItem item) { - // TODO Auto-generated method stub switch (item.getItemId()) { - case R.id.public_menu_send: - handleSubmit(); - break; - - default: - break; + case R.id.public_menu_send: + handleSubmit(); + break; } return super.onOptionsItemSelected(item); } @@ -302,17 +289,19 @@ public class TeamNewActiveActivity extends BaseActivity { public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { Result result = XmlUtils.toBean(ResultBean.class, arg2) .getResult(); - if (result != null && result.OK()) { - AppContext.showToast(result.getErrorMessage()); - finish(); - } else { - AppContext.showToast(result.getErrorMessage()); + if (result != null) { + if (result.OK()) { + AppContext.showToast(result.getErrorMessage()); + finish(); + } else { + AppContext.showToast(result.getErrorMessage()); + } } } @Override public void onFailure(int arg0, Header[] arg1, byte[] arg2, - Throwable arg3) { + Throwable arg3) { AppContext.showToast("发表失败,请检查下你的网络"); } @@ -327,7 +316,7 @@ public class TeamNewActiveActivity extends BaseActivity { super.onFinish(); hideWaitDialog(); } - }); + }, this); } @Override @@ -341,7 +330,7 @@ public class TeamNewActiveActivity extends BaseActivity { } private void showConfirmExit() { - DialogHelp.getConfirmDialog(this, "是否放弃这次操作?", new OnClickListener() { + DialogHelper.getConfirmDialog(this, "是否放弃这次操作?", new OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { finish(); @@ -350,12 +339,13 @@ public class TeamNewActiveActivity extends BaseActivity { } private void handleSelectPicture() { - DialogHelp.getSelectDialog(this, getResources().getStringArray(R.array.choose_picture), new OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - goToSelectPicture(i); - } - }).show(); + DialogHelper.getSelectDialog(this, getResources().getStringArray(R.array.choose_picture), "取消", + new OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + goToSelectPicture(i); + } + }).show(); } public static final int ACTION_TYPE_ALBUM = 0; @@ -363,62 +353,62 @@ public class TeamNewActiveActivity extends BaseActivity { private void goToSelectPicture(int position) { switch (position) { - case ACTION_TYPE_ALBUM: - Intent intent; - if (Build.VERSION.SDK_INT < 19) { - intent = new Intent(); - intent.setAction(Intent.ACTION_GET_CONTENT); - intent.setType("image/*"); - startActivityForResult(Intent.createChooser(intent, "选择图片"), - ImageUtils.REQUEST_CODE_GETIMAGE_BYSDCARD); - } else { - intent = new Intent(Intent.ACTION_PICK, - Images.Media.EXTERNAL_CONTENT_URI); - intent.setType("image/*"); - startActivityForResult(Intent.createChooser(intent, "选择图片"), - ImageUtils.REQUEST_CODE_GETIMAGE_BYSDCARD); - } - break; - case ACTION_TYPE_PHOTO: - // 判断是否挂载了SD卡 - String savePath = ""; - String storageState = Environment.getExternalStorageState(); - if (storageState.equals(Environment.MEDIA_MOUNTED)) { - savePath = Environment.getExternalStorageDirectory() - .getAbsolutePath() + "/oschina/Camera/"; - File savedir = new File(savePath); - if (!savedir.exists()) { - savedir.mkdirs(); + case ACTION_TYPE_ALBUM: + Intent intent; + if (Build.VERSION.SDK_INT < 19) { + intent = new Intent(); + intent.setAction(Intent.ACTION_GET_CONTENT); + intent.setType("image/*"); + startActivityForResult(Intent.createChooser(intent, "选择图片"), + ImageUtils.REQUEST_CODE_GETIMAGE_BYSDCARD); + } else { + intent = new Intent(Intent.ACTION_PICK, + Images.Media.EXTERNAL_CONTENT_URI); + intent.setType("image/*"); + startActivityForResult(Intent.createChooser(intent, "选择图片"), + ImageUtils.REQUEST_CODE_GETIMAGE_BYSDCARD); + } + break; + case ACTION_TYPE_PHOTO: + // 判断是否挂载了SD卡 + String savePath = ""; + String storageState = Environment.getExternalStorageState(); + if (storageState.equals(Environment.MEDIA_MOUNTED)) { + savePath = Environment.getExternalStorageDirectory() + .getAbsolutePath() + "/oschina/Camera/"; + File savedir = new File(savePath); + if (!savedir.exists()) { + savedir.mkdirs(); + } } - } - // 没有挂载SD卡,无法保存文件 - if (StringUtils.isEmpty(savePath)) { - AppContext.showToastShort("无法保存照片,请检查SD卡是否挂载"); - return; - } + // 没有挂载SD卡,无法保存文件 + if (StringUtils.isEmpty(savePath)) { + AppContext.showToastShort("无法保存照片,请检查SD卡是否挂载"); + return; + } - String timeStamp = new SimpleDateFormat("yyyyMMddHHmmss") - .format(new Date()); - String fileName = "osc_" + timeStamp + ".jpg";// 照片命名 - File out = new File(savePath, fileName); - Uri uri = Uri.fromFile(out); - - theLarge = savePath + fileName;// 该照片的绝对路径 - - intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); - intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); - startActivityForResult(intent, - ImageUtils.REQUEST_CODE_GETIMAGE_BYCAMERA); - break; - default: - break; + String timeStamp = new SimpleDateFormat("yyyyMMddHHmmss") + .format(new Date()); + String fileName = "osc_" + timeStamp + ".jpg";// 照片命名 + File out = new File(savePath, fileName); + Uri uri = Uri.fromFile(out); + + theLarge = savePath + fileName;// 该照片的绝对路径 + + intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); + startActivityForResult(intent, + ImageUtils.REQUEST_CODE_GETIMAGE_BYCAMERA); + break; + default: + break; } } @Override public void onActivityResult(final int requestCode, final int resultCode, - final Intent imageReturnIntent) { + final Intent imageReturnIntent) { if (resultCode != Activity.RESULT_OK) return; new Thread() { @@ -447,19 +437,16 @@ public class TeamNewActiveActivity extends BaseActivity { if (AppContext .isMethodsCompat(android.os.Build.VERSION_CODES.ECLAIR_MR1)) { String imaName = FileUtil.getFileName(theLarge); - if (imaName != null) - bitmap = ImageUtils.loadImgThumbnail( - TeamNewActiveActivity.this, imaName, - MediaStore.Images.Thumbnails.MICRO_KIND); + bitmap = ImageUtils.loadImgThumbnail( + TeamNewActiveActivity.this, imaName, + Images.Thumbnails.MICRO_KIND); } if (bitmap == null && !StringUtils.isEmpty(theLarge)) - bitmap = ImageUtils - .loadImgThumbnail(theLarge, 100, 100); + bitmap = ImageUtils.loadImgThumbnail(theLarge, 100, 100); } else if (requestCode == ImageUtils.REQUEST_CODE_GETIMAGE_BYCAMERA) { // 拍摄图片 - if (bitmap == null && !StringUtils.isEmpty(theLarge)) { - bitmap = ImageUtils - .loadImgThumbnail(theLarge, 100, 100); + if (!StringUtils.isEmpty(theLarge)) { + bitmap = ImageUtils.loadImgThumbnail(theLarge, 100, 100); } } @@ -505,7 +492,9 @@ public class TeamNewActiveActivity extends BaseActivity { msg.obj = bitmap; handler.sendMessage(msg); } - }; + } + + ; }.start(); } @@ -520,11 +509,9 @@ public class TeamNewActiveActivity extends BaseActivity { @Override public void onSuccess(int arg0, Header[] arg1, - byte[] arg2) { - // TODO Auto-generated method stub + byte[] arg2) { TeamMemberList memberList = XmlUtils.toBean( TeamMemberList.class, arg2); - if (memberList != null) { mTeamMemberList = memberList.getList(); showMetionUser(); @@ -535,21 +522,18 @@ public class TeamNewActiveActivity extends BaseActivity { @Override public void onFailure(int arg0, Header[] arg1, - byte[] arg2, Throwable arg3) { - // TODO Auto-generated method stub + byte[] arg2, Throwable arg3) { AppContext.showToast("获取团队成员失败"); } @Override public void onStart() { - // TODO Auto-generated method stub super.onStart(); showWaitDialog("正在获取团队成员..."); } @Override public void onFinish() { - // TODO Auto-generated method stub super.onFinish(); hideWaitDialog(); } @@ -573,17 +557,17 @@ public class TeamNewActiveActivity extends BaseActivity { for (int i = 1; i < toUsers.length; i++) { toUsers[i] = mTeamMemberList.get(i - 1).getName(); } - metionUserDialog = DialogHelp.getSingleChoiceDialog(this, "艾特团队成员", toUsers, -1, new OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - // TODO Auto-generated method st - mEtInput.getText().insert(mEtInput.getSelectionStart(), - "@" + toUsers[i] + " "); - mEtInput.setSelection(mEtInput.length()); - metionUserDialog.dismiss(); + metionUserDialog = DialogHelper.getSingleChoiceDialog(this, "艾特团队成员", toUsers, -1, new + OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + mEtInput.getText().insert(mEtInput.getSelectionStart(), + "@" + toUsers[i] + " "); + mEtInput.setSelection(mEtInput.length()); + metionUserDialog.dismiss(); - } - }).show(); + } + }).show(); } metionUserDialog.show(); diff --git a/app/src/main/java/net/oschina/app/team/ui/TeamNewIssueActivity.java b/app/src/main/java/net/oschina/app/team/ui/TeamNewIssueActivity.java index 30b28f302e8af6f5e3f2450e21899397ff4a23fe..d55119f190b2c93558ff730ea0bb41243e608f22 100644 --- a/app/src/main/java/net/oschina/app/team/ui/TeamNewIssueActivity.java +++ b/app/src/main/java/net/oschina/app/team/ui/TeamNewIssueActivity.java @@ -24,6 +24,8 @@ import net.oschina.app.api.remote.OSChinaTeamApi; import net.oschina.app.base.BaseActivity; import net.oschina.app.bean.Result; import net.oschina.app.bean.ResultBean; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.utils.DialogHelper; import net.oschina.app.team.bean.Team; import net.oschina.app.team.bean.TeamGit; import net.oschina.app.team.bean.TeamIssue; @@ -33,46 +35,45 @@ import net.oschina.app.team.bean.TeamMember; import net.oschina.app.team.bean.TeamMemberList; import net.oschina.app.team.bean.TeamProject; import net.oschina.app.team.bean.TeamProjectList; -import net.oschina.app.util.DialogHelp; import net.oschina.app.util.TypefaceUtils; import net.oschina.app.util.XmlUtils; -import cz.msebera.android.httpclient.Header; import java.util.Calendar; import java.util.List; -import butterknife.InjectView; +import butterknife.Bind; import butterknife.OnClick; +import cz.msebera.android.httpclient.Header; /** * Created by 火蚁 on 15/5/28. */ public class TeamNewIssueActivity extends BaseActivity { - @InjectView(R.id.et_issue_title) + @Bind(R.id.et_issue_title) EditText mEtTitle; - @InjectView(R.id.tv_issue_project) + @Bind(R.id.tv_issue_project) TextView mTvProject; - @InjectView(R.id.tv_issue_catalog) + @Bind(R.id.tv_issue_catalog) TextView mTvCatalog; - @InjectView(R.id.tv_issue_touser) + @Bind(R.id.tv_issue_touser) TextView mTvToUser; - @InjectView(R.id.tv_issue_time) + @Bind(R.id.tv_issue_time) TextView mTvTime; - @InjectView(R.id.rl_issue_push) + @Bind(R.id.rl_issue_push) View mRlGitPush; - @InjectView(R.id.push_line) + @Bind(R.id.push_line) View mPushLine; - @InjectView(R.id.tv_issue_push_source) + @Bind(R.id.tv_issue_push_source) TextView mTvPushSource; - @InjectView(R.id.cb_issue_push_check) + @Bind(R.id.cb_issue_push_check) CheckBox mCbPush; private Team mTeam; @@ -96,24 +97,18 @@ public class TeamNewIssueActivity extends BaseActivity { @Override public void initView() { mEtTitle.addTextChangedListener(new TextWatcher() { - @Override public void onTextChanged(CharSequence s, int start, int before, int count) { - // TODO Auto-generated method stub - } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { - // TODO Auto-generated method stub - } @Override public void afterTextChanged(Editable s) { - // TODO Auto-generated method stub updateMenuState(); } }); @@ -135,10 +130,10 @@ public class TeamNewIssueActivity extends BaseActivity { private void updateMenuState() { if (mEtTitle.getText().length() == 0) { mSendMenu.setEnabled(false); - mSendMenu.setIcon(R.drawable.actionbar_unsend_icon); + mSendMenu.setIcon(R.mipmap.actionbar_unsend_icon); } else { mSendMenu.setEnabled(true); - mSendMenu.setIcon(R.drawable.actionbar_send_icon); + mSendMenu.setIcon(R.mipmap.actionbar_send_icon); } } @@ -158,7 +153,6 @@ public class TeamNewIssueActivity extends BaseActivity { @Override public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { - // TODO Auto-generated method stub Result res = XmlUtils.toBean(ResultBean.class, arg2).getResult(); if (res.OK()) { AppContext.showToast(res.getErrorMessage()); @@ -171,19 +165,17 @@ public class TeamNewIssueActivity extends BaseActivity { @Override public void onFailure(int arg0, Header[] arg1, byte[] arg2, Throwable arg3) { - // TODO Auto-generated method stub - } @Override public void onFinish() { hideWaitDialog(); - }; + } @Override public void onStart() { showWaitDialog("发布中..."); - }; + } }; private void sendPubNewIssue() { @@ -195,7 +187,7 @@ public class TeamNewIssueActivity extends BaseActivity { RequestParams params = new RequestParams(); params.put("teamid", mTeam.getId()); - params.put("uid", AppContext.getInstance().getLoginUid()); + params.put("uid", AccountHelper.getUserId()); params.put("title", title); if (mTeamProject.getGit().getId() > 0) { @@ -296,22 +288,22 @@ public class TeamNewIssueActivity extends BaseActivity { } } } - projectDialog = DialogHelp.getSingleChoiceDialog(this, "指定项目", arrays, projectIndex, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - // TODO Auto-generated method stub - if (i == projectIndex) { - projectDialog.dismiss(); - return; - } - projectIndex = i; - mTvProject.setText(arrays[i]); - mTeamProject = projects.get(i); - checkIsShowPush(); - clearCatalogAndToUser(); - projectDialog.dismiss(); - } - }).show(); + projectDialog = DialogHelper.getSingleChoiceDialog(this, "指定项目", arrays, projectIndex, new + DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + if (i == projectIndex) { + projectDialog.dismiss(); + return; + } + projectIndex = i; + mTvProject.setText(arrays[i]); + mTeamProject = projects.get(i); + checkIsShowPush(); + clearCatalogAndToUser(); + projectDialog.dismiss(); + } + }).show(); } private void showTeamCatalogSelected(final List list) { @@ -325,15 +317,16 @@ public class TeamNewIssueActivity extends BaseActivity { } } } - catalogDialog = DialogHelp.getSingleChoiceDialog(this, "指定任务列表", catalogs, catalogIndex, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - catalogIndex = i; - mTeamCatalog = list.get(i); - mTvCatalog.setText(catalogs[i]); - catalogDialog.dismiss(); - } - }).show(); + catalogDialog = DialogHelper.getSingleChoiceDialog(this, "指定任务列表", catalogs, catalogIndex, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + catalogIndex = i; + mTeamCatalog = list.get(i); + mTvCatalog.setText(catalogs[i]); + catalogDialog.dismiss(); + } + }).show(); } private void showIssueToUser(List list) { @@ -346,14 +339,15 @@ public class TeamNewIssueActivity extends BaseActivity { for (int i = 0; i < list.size(); i++) { toUsers[i] = list.get(i).getName(); } - toUserDialog = DialogHelp.getSingleChoiceDialog(this, "指派成员", toUsers, toUserIndex, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - toUserIndex = i; - mTvToUser.setText(toUsers[i]); - toUserDialog.dismiss(); - } - }).show(); + toUserDialog = DialogHelper.getSingleChoiceDialog(this, "指派成员", toUsers, toUserIndex, new + DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + toUserIndex = i; + mTvToUser.setText(toUsers[i]); + toUserDialog.dismiss(); + } + }).show(); toUserDialog.show(); } @@ -414,7 +408,6 @@ public class TeamNewIssueActivity extends BaseActivity { @Override public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { - // TODO Auto-generated method stub } }, mYear, mMonth, mDay); @@ -422,10 +415,8 @@ public class TeamNewIssueActivity extends BaseActivity { @Override public void onClick(DialogInterface dialog, int which) { - // TODO Auto-generated method stub switch (which) { case DialogInterface.BUTTON_NEGATIVE: - break; case DialogInterface.BUTTON_NEUTRAL: issueTime = ""; @@ -484,8 +475,7 @@ public class TeamNewIssueActivity extends BaseActivity { } private void tryToShowCatalogDialog() { - OSChinaTeamApi.getTeamCatalogIssueList(AppContext.getInstance() - .getLoginUid(), mTeam.getId(), mTeamProject.getGit().getId(), + OSChinaTeamApi.getTeamCatalogIssueList((int) AccountHelper.getUserId(), mTeam.getId(), mTeamProject.getGit().getId(), mTeamProject.getSource(), new MySomeInfoHandler( show_issue_catalog)); @@ -493,7 +483,7 @@ public class TeamNewIssueActivity extends BaseActivity { private void tryToShowToUserDilaog() { OSChinaTeamApi.getTeamProjectMemberList(mTeam.getId(), mTeamProject, - new MySomeInfoHandler(show_issue_touser)); + new MySomeInfoHandler(show_issue_touser), getApplicationContext()); } public class MySomeInfoHandler extends AsyncHttpResponseHandler { @@ -506,14 +496,12 @@ public class TeamNewIssueActivity extends BaseActivity { @Override public void onFinish() { - // TODO Auto-generated method stub super.onFinish(); hideWaitDialog(); } @Override public void onStart() { - // TODO Auto-generated method stub super.onStart(); showWaitDialog("获取中..."); } @@ -521,13 +509,11 @@ public class TeamNewIssueActivity extends BaseActivity { @Override public void onFailure(int arg0, Header[] arg1, byte[] arg2, Throwable arg3) { - // TODO Auto-generated method stub showFaile(); } @Override public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { - // TODO Auto-generated method stub switch (showType) { // 显示项目选择对话框 case show_project: diff --git a/app/src/main/java/net/oschina/app/team/viewpagefragment/TeamDiaryFragment.java b/app/src/main/java/net/oschina/app/team/viewpagefragment/TeamDiaryFragment.java index 4cb96f9edb19610260c430f87d0f4070c883412e..3239aa82890ce1763a9304e02df5e57af0ac8445 100644 --- a/app/src/main/java/net/oschina/app/team/viewpagefragment/TeamDiaryFragment.java +++ b/app/src/main/java/net/oschina/app/team/viewpagefragment/TeamDiaryFragment.java @@ -1,9 +1,17 @@ package net.oschina.app.team.viewpagefragment; -import java.util.Calendar; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; +import android.app.Activity; +import android.os.Bundle; +import android.support.v4.view.ViewPager; +import android.support.v4.view.ViewPager.OnPageChangeListener; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.fourmob.datetimepicker.date.DatePickerDialog; +import com.fourmob.datetimepicker.date.DatePickerDialog.OnDateSetListener; import net.oschina.app.AppContext; import net.oschina.app.R; @@ -17,20 +25,13 @@ import net.oschina.app.util.StringUtils; import org.kymjs.kjframe.http.KJAsyncTask; -import android.app.Activity; -import android.os.Bundle; -import android.support.v4.view.ViewPager; -import android.support.v4.view.ViewPager.OnPageChangeListener; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; -import butterknife.ButterKnife; -import butterknife.InjectView; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; -import com.fourmob.datetimepicker.date.DatePickerDialog; -import com.fourmob.datetimepicker.date.DatePickerDialog.OnDateSetListener; +import butterknife.Bind; +import butterknife.ButterKnife; public class TeamDiaryFragment extends BaseFragment implements OnDateSetListener { @@ -38,15 +39,15 @@ public class TeamDiaryFragment extends BaseFragment implements public static String DIARYDETAIL_KEY = "team_diary_detail_key"; public static String TEAMID_KEY = "team_diary_teamid_key"; - @InjectView(R.id.team_diary_pager) + @Bind(R.id.team_diary_pager) ViewPager mPager; - @InjectView(R.id.team_diary_pager_title) + @Bind(R.id.team_diary_pager_title) TextView mTvTitle; - @InjectView(R.id.team_diary_pager_calendar) + @Bind(R.id.team_diary_pager_calendar) ImageView mImgCalendar; - @InjectView(R.id.team_diary_pager_left) + @Bind(R.id.team_diary_pager_left) ImageView mImgLeft; - @InjectView(R.id.team_diary_pager_right) + @Bind(R.id.team_diary_pager_right) ImageView mImgRight; private Activity aty; @@ -59,11 +60,11 @@ public class TeamDiaryFragment extends BaseFragment implements @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { + Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); aty = getActivity(); View view = View.inflate(aty, R.layout.fragment_team_diarypager, null); - ButterKnife.inject(this, view); + ButterKnife.bind(this, view); initData(); initView(view); return view; @@ -77,9 +78,11 @@ public class TeamDiaryFragment extends BaseFragment implements team = (Team) bundle .getSerializable(TeamMainActivity.BUNDLE_KEY_TEAM); } - TAG += team.getId(); + if (team != null) { + TAG += team.getId(); + } currentWeek = StringUtils.getWeekOfYear() - 1; - dataBundleList = new HashMap(currentWeek + 5); + dataBundleList = new HashMap<>(currentWeek + 5); // 异步读缓存 KJAsyncTask.execute(new Runnable() { @Override @@ -107,81 +110,81 @@ public class TeamDiaryFragment extends BaseFragment implements mImgCalendar.setOnClickListener(this); mImgLeft.setOnClickListener(this); mImgRight.setOnClickListener(this); - mPager.setOnPageChangeListener(new OnPageChangeListener() { + mPager.addOnPageChangeListener(new OnPageChangeListener() { @Override public void onPageSelected(int arg0) { changeUI(arg0, mPager.getAdapter().getCount()); } @Override - public void onPageScrolled(int arg0, float arg1, int arg2) {} + public void onPageScrolled(int arg0, float arg1, int arg2) { + } @Override - public void onPageScrollStateChanged(int arg0) {} + public void onPageScrollStateChanged(int arg0) { + } }); } /** * 改变Title - * - * @param currentPage - * 当前页(从0开始) - * @param totalPage - * 总共有多少页(从0开始) + * + * @param currentPage 当前页(从0开始) + * @param totalPage 总共有多少页(从0开始) */ private void changeUI(int currentPage, int totalPage) { mPager.setCurrentItem(currentPage); if (currentPage <= 0) { - mImgLeft.setImageResource(R.drawable.ic_diary_back); + mImgLeft.setImageResource(R.mipmap.ic_diary_back); } else { - mImgLeft.setImageResource(R.drawable.ic_diary_canback); + mImgLeft.setImageResource(R.mipmap.ic_diary_canback); } if (currentPage >= adapter.getCount() - 1) { - mImgRight.setImageResource(R.drawable.ic_diary_forward); + mImgRight.setImageResource(R.mipmap.ic_diary_forward); } else { - mImgRight.setImageResource(R.drawable.ic_diary_canforward); + mImgRight.setImageResource(R.mipmap.ic_diary_canforward); } - mTvTitle.setText("第" + (currentPage + 1) + "周周报总览"); + mTvTitle.setText(String.format("第%d周周报总览", currentPage + 1)); } @Override public void onClick(View v) { super.onClick(v); switch (v.getId()) { - case R.id.team_diary_pager_right: - int currentPage1 = mPager.getCurrentItem(); - if (currentPage1 < mPager.getAdapter().getCount()) { - mPager.setCurrentItem(currentPage1 + 1); - } - break; - case R.id.team_diary_pager_left: - int currentPage2 = mPager.getCurrentItem(); - if (currentPage2 > 0) { - mPager.setCurrentItem(currentPage2 - 1); - } - break; - case R.id.team_diary_pager_calendar: - final DatePickerDialog datePickerDialog = DatePickerDialog - .newInstance(this, calendar.get(Calendar.YEAR), - calendar.get(Calendar.MONTH), - calendar.get(Calendar.DAY_OF_MONTH), false); - datePickerDialog.setVibrate(false); - datePickerDialog.setYearRange(2014, 2015); - datePickerDialog.show(getFragmentManager(), "datepicker"); - break; - default: - break; + case R.id.team_diary_pager_right: + int currentPage1 = mPager.getCurrentItem(); + if (currentPage1 < mPager.getAdapter().getCount()) { + mPager.setCurrentItem(currentPage1 + 1); + } + break; + case R.id.team_diary_pager_left: + int currentPage2 = mPager.getCurrentItem(); + if (currentPage2 > 0) { + mPager.setCurrentItem(currentPage2 - 1); + } + break; + case R.id.team_diary_pager_calendar: + final DatePickerDialog datePickerDialog = DatePickerDialog + .newInstance(this, calendar.get(Calendar.YEAR), + calendar.get(Calendar.MONTH), + calendar.get(Calendar.DAY_OF_MONTH), false); + datePickerDialog.setVibrate(false); + datePickerDialog.setYearRange(2014, 2015); + datePickerDialog.show(getFragmentManager(), "datepicker"); + break; + default: + break; } } @Override public void onDateSet(DatePickerDialog datePickerDialog, int year, - int month, int day) { + int month, int day) { int[] dateBundle = StringUtils.getCurrentDate(); if ((dateBundle[0] == year && dateBundle[1] <= month) || (dateBundle[0] == year && dateBundle[1] == month + 1 && dateBundle[2] < day)) { - AppContext.showToast("那天怎么会有周报呢"); + AppContext.showToast("这天怎么会有周报呢"); } else { currentYear = year; currentWeek = StringUtils.getWeekOfYear(new Date(year, month, day)) - 1; diff --git a/app/src/main/java/net/oschina/app/team/viewpagefragment/TeamIssueViewPageFragment.java b/app/src/main/java/net/oschina/app/team/viewpagefragment/TeamIssueViewPageFragment.java index 52e3862af5ac116ac0b272ac6854d6186563f372..cc9fb5a33595e91dc43e1b90516ee4bca88dacb4 100644 --- a/app/src/main/java/net/oschina/app/team/viewpagefragment/TeamIssueViewPageFragment.java +++ b/app/src/main/java/net/oschina/app/team/viewpagefragment/TeamIssueViewPageFragment.java @@ -1,13 +1,18 @@ package net.oschina.app.team.viewpagefragment; -import java.io.ByteArrayInputStream; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; + +import com.loopj.android.http.AsyncHttpResponseHandler; -import net.oschina.app.AppContext; import net.oschina.app.R; import net.oschina.app.adapter.ViewPageFragmentAdapter; import net.oschina.app.api.remote.OSChinaTeamApi; import net.oschina.app.base.BaseActivity; import net.oschina.app.base.BaseViewPagerFragment; +import net.oschina.app.improve.account.AccountHelper; import net.oschina.app.team.bean.Team; import net.oschina.app.team.bean.TeamGit; import net.oschina.app.team.bean.TeamIssueCatalog; @@ -22,13 +27,9 @@ import net.oschina.app.util.StringUtils; import net.oschina.app.util.UIHelper; import net.oschina.app.util.XmlUtils; -import cz.msebera.android.httpclient.Header; -import android.os.Bundle; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; +import java.io.ByteArrayInputStream; -import com.loopj.android.http.AsyncHttpResponseHandler; +import cz.msebera.android.httpclient.Header; /** * Team 任务列表viewpager @@ -157,7 +158,7 @@ public class TeamIssueViewPageFragment extends BaseViewPagerFragment { } private void sendRequestCatalogList() { - int uid = AppContext.getInstance().getLoginUid(); + int uid = (int) AccountHelper.getUserId(); OSChinaTeamApi.getTeamCatalogIssueList(uid, mTeamId, mProjectId, "", handler); } diff --git a/app/src/main/java/net/oschina/app/team/viewpagefragment/TeamMainViewPagerFragment.java b/app/src/main/java/net/oschina/app/team/viewpagefragment/TeamMainViewPagerFragment.java index 8f70f88c81f13d6cab8d79aa586edf5a599415c7..4816eee235254d34f23222cfc705f571aea92843 100644 --- a/app/src/main/java/net/oschina/app/team/viewpagefragment/TeamMainViewPagerFragment.java +++ b/app/src/main/java/net/oschina/app/team/viewpagefragment/TeamMainViewPagerFragment.java @@ -1,5 +1,13 @@ package net.oschina.app.team.viewpagefragment; +import android.content.Intent; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.widget.FrameLayout; + import net.oschina.app.R; import net.oschina.app.adapter.ViewPageFragmentAdapter; import net.oschina.app.base.BaseViewPagerFragment; @@ -10,18 +18,11 @@ import net.oschina.app.team.fragment.TeamMemberFragment; import net.oschina.app.team.ui.TeamMainActivity; import net.oschina.app.team.ui.TeamNewActiveActivity; import net.oschina.app.util.UIHelper; -import android.content.Intent; -import android.os.Bundle; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; /** * Team主界面 - * + * * @author kymjs (https://github.com/kymjs) - * */ public class TeamMainViewPagerFragment extends BaseViewPagerFragment { @@ -36,14 +37,14 @@ public class TeamMainViewPagerFragment extends BaseViewPagerFragment { @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case R.id.team_new_active: - showCreateNewActive(); - break; - case R.id.team_new_issue: - UIHelper.showCreateNewIssue(getActivity(), mTeam, null, null); - break; - default: - break; + case R.id.team_new_active: + showCreateNewActive(); + break; + case R.id.team_new_issue: + UIHelper.showCreateNewIssue(getActivity(), mTeam, null, null); + break; + default: + break; } return super.onOptionsItemSelected(item); } @@ -85,6 +86,10 @@ public class TeamMainViewPagerFragment extends BaseViewPagerFragment { @Override protected void onSetupTabAdapter(ViewPageFragmentAdapter adapter) { + + FrameLayout generalActionBar = (FrameLayout) mRoot.findViewById(R.id.general_actionbar); + generalActionBar.setVisibility(View.GONE); + String[] arraStrings = getResources().getStringArray( R.array.team_main_viewpager); diff --git a/app/src/main/java/net/oschina/app/team/viewpagefragment/TeamProjectViewPagerFragment.java b/app/src/main/java/net/oschina/app/team/viewpagefragment/TeamProjectViewPagerFragment.java index 254bfa2929c60fc65a3d055bd46e66b26b275781..e9e1b83e95052dfda9d747b26163096d835c7226 100644 --- a/app/src/main/java/net/oschina/app/team/viewpagefragment/TeamProjectViewPagerFragment.java +++ b/app/src/main/java/net/oschina/app/team/viewpagefragment/TeamProjectViewPagerFragment.java @@ -1,10 +1,14 @@ package net.oschina.app.team.viewpagefragment; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; + import net.oschina.app.R; import net.oschina.app.adapter.ViewPageFragmentAdapter; import net.oschina.app.base.BaseActivity; import net.oschina.app.base.BaseViewPagerFragment; -import net.oschina.app.fragment.NewsFragment; import net.oschina.app.team.bean.Team; import net.oschina.app.team.bean.TeamProject; import net.oschina.app.team.fragment.TeamIssueCatalogFragment; @@ -12,24 +16,19 @@ import net.oschina.app.team.fragment.TeamProjectActiveFragment; import net.oschina.app.team.fragment.TeamProjectMemberFragment; import net.oschina.app.team.ui.TeamMainActivity; import net.oschina.app.util.UIHelper; -import android.os.Bundle; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; /** * TeamProjectViewPagerFragment.java - * - * @author 火蚁(http://my.oschina.net/u/253900) * + * @author 火蚁(http://my.oschina.net/u/253900) * @data 2015-3-1 下午2:23:32 */ public class TeamProjectViewPagerFragment extends BaseViewPagerFragment { - + private Team mTeam; - + private TeamProject mTeamProject; - + @Override public void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub @@ -38,45 +37,45 @@ public class TeamProjectViewPagerFragment extends BaseViewPagerFragment { if (args != null) { mTeam = (Team) args.getSerializable(TeamMainActivity.BUNDLE_KEY_TEAM); mTeamProject = (TeamProject) args.getSerializable(TeamMainActivity.BUNDLE_KEY_PROJECT); - ((BaseActivity)getActivity()).setActionBarTitle(mTeamProject.getGit().getName()); + ((BaseActivity) getActivity()).setActionBarTitle(mTeamProject.getGit().getName()); } setHasOptionsMenu(true); } - + @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { // TODO Auto-generated method stub super.onCreateOptionsMenu(menu, inflater); inflater.inflate(R.menu.team_project_menu, menu); } - + @Override public boolean onOptionsItemSelected(MenuItem item) { // TODO Auto-generated method stub - int menuId = item.getItemId(); - switch (menuId) { - case R.id.team_new_issue: - UIHelper.showCreateNewIssue(getActivity(), mTeam, mTeamProject, null); - break; + int menuId = item.getItemId(); + switch (menuId) { + case R.id.team_new_issue: + UIHelper.showCreateNewIssue(getActivity(), mTeam, mTeamProject, null); + break; - default: - break; - } + default: + break; + } return super.onOptionsItemSelected(item); } - + @Override protected void onSetupTabAdapter(ViewPageFragmentAdapter adapter) { - adapter.addTab("任务分组", "issue", TeamIssueCatalogFragment.class, getBundle()); - adapter.addTab("动态", "active", TeamProjectActiveFragment.class, getBundle()); - adapter.addTab("成员", "member", TeamProjectMemberFragment.class, getBundle()); + adapter.addTab("任务分组", "issue", TeamIssueCatalogFragment.class, getBundle()); + adapter.addTab("动态", "active", TeamProjectActiveFragment.class, getBundle()); + adapter.addTab("成员", "member", TeamProjectMemberFragment.class, getBundle()); } - + private Bundle getBundle() { - Bundle bundle = new Bundle(); - bundle.putSerializable(TeamMainActivity.BUNDLE_KEY_TEAM, mTeam); - bundle.putSerializable(TeamMainActivity.BUNDLE_KEY_PROJECT, mTeamProject); - return bundle; + Bundle bundle = new Bundle(); + bundle.putSerializable(TeamMainActivity.BUNDLE_KEY_TEAM, mTeam); + bundle.putSerializable(TeamMainActivity.BUNDLE_KEY_PROJECT, mTeamProject); + return bundle; } } diff --git a/app/src/main/java/net/oschina/app/ui/DetailActivity.java b/app/src/main/java/net/oschina/app/ui/DetailActivity.java index 7840ef91457275b901125c5d27ac05362e7d0fad..aea10f52697d9993c4122251dc4ab0a0a227b7e0 100644 --- a/app/src/main/java/net/oschina/app/ui/DetailActivity.java +++ b/app/src/main/java/net/oschina/app/ui/DetailActivity.java @@ -1,5 +1,6 @@ package net.oschina.app.ui; +import android.content.Intent; import android.os.Bundle; import android.support.v4.app.FragmentTransaction; import android.text.Editable; @@ -15,13 +16,6 @@ import net.oschina.app.emoji.OnSendClickListener; import net.oschina.app.emoji.ToolbarFragment; import net.oschina.app.emoji.ToolbarFragment.OnActionClickListener; import net.oschina.app.emoji.ToolbarFragment.ToolAction; -import net.oschina.app.fragment.BlogDetailFragment; -import net.oschina.app.fragment.CommentFrament; -import net.oschina.app.fragment.EventDetailFragment; -import net.oschina.app.fragment.NewsDetailFragment; -import net.oschina.app.fragment.PostDetailFragment; -import net.oschina.app.fragment.SoftwareDetailFragment; -import net.oschina.app.fragment.TweetDetailFragment; import net.oschina.app.team.fragment.TeamDiaryDetailFragment; import net.oschina.app.team.fragment.TeamDiscussDetailFragment; import net.oschina.app.team.fragment.TeamIssueDetailFragment; @@ -34,13 +28,7 @@ import net.oschina.app.team.fragment.TeamTweetDetailFragment; * @created 2014年10月11日 上午11:18:41 */ public class DetailActivity extends BaseActivity implements OnSendClickListener { - - public static final int DISPLAY_NEWS = 0; - public static final int DISPLAY_BLOG = 1; - public static final int DISPLAY_SOFTWARE = 2; - public static final int DISPLAY_POST = 3; public static final int DISPLAY_TWEET = 4; - public static final int DISPLAY_EVENT = 5; public static final int DISPLAY_TEAM_ISSUE_DETAIL = 6; public static final int DISPLAY_TEAM_DISCUSS_DETAIL = 7; public static final int DISPLAY_TEAM_TWEET_DETAIL = 8; @@ -71,35 +59,13 @@ public class DetailActivity extends BaseActivity implements OnSendClickListener @Override protected void init(Bundle savedInstanceState) { super.init(savedInstanceState); - int displayType = getIntent().getIntExtra(BUNDLE_KEY_DISPLAY_TYPE, - DISPLAY_NEWS); + int displayType = getIntent().getIntExtra(BUNDLE_KEY_DISPLAY_TYPE, 0); BaseFragment fragment = null; int actionBarTitle = 0; switch (displayType) { - case DISPLAY_NEWS: - actionBarTitle = R.string.actionbar_title_news; - fragment = new NewsDetailFragment(); - break; - case DISPLAY_BLOG: - actionBarTitle = R.string.actionbar_title_blog; - fragment = new BlogDetailFragment(); - break; - case DISPLAY_SOFTWARE: - actionBarTitle = R.string.actionbar_title_software; - fragment = new SoftwareDetailFragment(); - break; - case DISPLAY_POST: - actionBarTitle = R.string.actionbar_title_question; - fragment = new PostDetailFragment(); - break; case DISPLAY_TWEET: - actionBarTitle = R.string.actionbar_title_tweet; - fragment = new TweetDetailFragment(); - break; - case DISPLAY_EVENT: - actionBarTitle = R.string.actionbar_title_event_detail; - fragment = new EventDetailFragment(); - break; + finish(); + return; case DISPLAY_TEAM_ISSUE_DETAIL: actionBarTitle = R.string.team_issue_detail; fragment = new TeamIssueDetailFragment(); @@ -116,10 +82,8 @@ public class DetailActivity extends BaseActivity implements OnSendClickListener actionBarTitle = R.string.team_diary_detail; fragment = new TeamDiaryDetailFragment(); break; - case DISPLAY_COMMENT: - actionBarTitle = R.string.actionbar_title_comment; - fragment = new CommentFrament(); default: + finish(); break; } setActionBarTitle(actionBarTitle); @@ -127,7 +91,7 @@ public class DetailActivity extends BaseActivity implements OnSendClickListener .beginTransaction(); trans.replace(R.id.container, fragment); trans.commitAllowingStateLoss(); - if (fragment instanceof OnSendClickListener) { + if (fragment != null && fragment instanceof OnSendClickListener) { currentFragment = (OnSendClickListener) fragment; } else { currentFragment = new OnSendClickListener() { @@ -148,12 +112,10 @@ public class DetailActivity extends BaseActivity implements OnSendClickListener @Override public void initView() { - if (currentFragment instanceof TweetDetailFragment - || currentFragment instanceof TeamTweetDetailFragment + if (currentFragment instanceof TeamTweetDetailFragment || currentFragment instanceof TeamDiaryDetailFragment || currentFragment instanceof TeamIssueDetailFragment - || currentFragment instanceof TeamDiscussDetailFragment - || currentFragment instanceof CommentFrament) { + || currentFragment instanceof TeamDiscussDetailFragment) { getSupportFragmentManager().beginTransaction() .replace(R.id.emoji_keyboard, emojiFragment).commit(); } else { @@ -223,13 +185,6 @@ public class DetailActivity extends BaseActivity implements OnSendClickListener return super.onKeyDown(keyCode, event); } - public void setCommentCount(int count) { - try { - toolFragment.setCommentCount(count); - } catch (Exception e) { - } - } - @Override public void onClickFlagButton() { getSupportFragmentManager() @@ -237,9 +192,16 @@ public class DetailActivity extends BaseActivity implements OnSendClickListener .setCustomAnimations(R.anim.footer_menu_slide_in, R.anim.footer_menu_slide_out) .replace(R.id.emoji_keyboard, toolFragment).commit(); - try { + } - } catch (Exception e) { + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (currentFragment instanceof CommonDetailFragment) { + //UMSsoHandler ssoHandler = ((CommonDetailFragment) currentFragment).getDialog().getController().getConfig().getSsoHandler(requestCode); + // if (ssoHandler != null) { + // ssoHandler.authorizeCallBack(requestCode, resultCode, data); + // } } } } diff --git a/app/src/main/java/net/oschina/app/ui/DoubleClickExitHelper.java b/app/src/main/java/net/oschina/app/ui/DoubleClickExitHelper.java deleted file mode 100644 index d1de225461fc6f200288456e4b0eed518d619e6d..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/ui/DoubleClickExitHelper.java +++ /dev/null @@ -1,67 +0,0 @@ -package net.oschina.app.ui; - -import net.oschina.app.AppManager; -import net.oschina.app.R; -import android.app.Activity; -import android.os.Handler; -import android.os.Looper; -import android.view.KeyEvent; -import android.widget.Toast; - - -/*** - * 双击退出 - * @author FireAnt(http://my.oschina.net/LittleDY) - * @created 2015年1月5日 下午7:07:44 - * - */ -public class DoubleClickExitHelper { - - private final Activity mActivity; - - private boolean isOnKeyBacking; - private Handler mHandler; - private Toast mBackToast; - - public DoubleClickExitHelper(Activity activity) { - mActivity = activity; - mHandler = new Handler(Looper.getMainLooper()); - } - - /** - * Activity onKeyDown事件 - * */ - public boolean onKeyDown(int keyCode, KeyEvent event) { - if(keyCode != KeyEvent.KEYCODE_BACK) { - return false; - } - if(isOnKeyBacking) { - mHandler.removeCallbacks(onBackTimeRunnable); - if(mBackToast != null){ - mBackToast.cancel(); - } - // 退出 - AppManager.getAppManager().AppExit(mActivity); - return true; - } else { - isOnKeyBacking = true; - if(mBackToast == null) { - mBackToast = Toast.makeText(mActivity, R.string.tip_double_click_exit, 2000); - } - mBackToast.show(); - mHandler.postDelayed(onBackTimeRunnable, 2000); - return true; - } - } - - private Runnable onBackTimeRunnable = new Runnable() { - - @Override - public void run() { - isOnKeyBacking = false; - if(mBackToast != null){ - mBackToast.cancel(); - } - } - }; -} diff --git a/app/src/main/java/net/oschina/app/ui/EventLocationActivity.java b/app/src/main/java/net/oschina/app/ui/EventLocationActivity.java deleted file mode 100644 index 906ffdeaef03e5364efcba2842180709fa3fb039..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/ui/EventLocationActivity.java +++ /dev/null @@ -1,224 +0,0 @@ -package net.oschina.app.ui; - -import net.oschina.app.AppContext; -import net.oschina.app.R; -import net.oschina.app.base.BaseActivity; -import android.annotation.SuppressLint; -import android.annotation.TargetApi; -import android.content.Intent; -import android.os.Build; -import android.os.Bundle; -import android.view.View; -import android.widget.TextView; - -import com.baidu.location.BDLocation; -import com.baidu.location.BDLocationListener; -import com.baidu.location.LocationClient; -import com.baidu.location.LocationClientOption; -import com.baidu.mapapi.SDKInitializer; -import com.baidu.mapapi.map.BaiduMap; -import com.baidu.mapapi.map.BitmapDescriptorFactory; -import com.baidu.mapapi.map.InfoWindow; -import com.baidu.mapapi.map.InfoWindow.OnInfoWindowClickListener; -import com.baidu.mapapi.map.MapStatusUpdate; -import com.baidu.mapapi.map.MapStatusUpdateFactory; -import com.baidu.mapapi.map.MapView; -import com.baidu.mapapi.map.Marker; -import com.baidu.mapapi.map.MarkerOptions; -import com.baidu.mapapi.model.LatLng; -import com.baidu.mapapi.navi.BaiduMapAppNotSupportNaviException; -import com.baidu.mapapi.navi.BaiduMapNavigation; -import com.baidu.mapapi.navi.NaviPara; -import com.baidu.mapapi.search.core.SearchResult; -import com.baidu.mapapi.search.geocode.GeoCodeOption; -import com.baidu.mapapi.search.geocode.GeoCodeResult; -import com.baidu.mapapi.search.geocode.GeoCoder; -import com.baidu.mapapi.search.geocode.OnGetGeoCoderResultListener; -import com.baidu.mapapi.search.geocode.ReverseGeoCodeResult; - - -/** - * 活动地图位置显示 - * - * @author FireAnt(http://my.oschina.net/LittleDY) - * @created 2014年12月15日 下午1:28:28 - * - */ -@SuppressLint("InflateParams") -@TargetApi(Build.VERSION_CODES.HONEYCOMB) -public class EventLocationActivity extends BaseActivity implements - OnGetGeoCoderResultListener { - - GeoCoder mSearch = null; // 搜索模块,也可去掉地图模块独立使用 - BaiduMap mBaiduMap = null; - MapView mMapView = null; - - private String mCity; - - private String mLocation; - - @Override - protected boolean hasBackButton() { - return true; - } - - @Override - protected int getActionBarTitle() { - return R.string.actionbar_title_event_location; - } - - protected void onCreate(Bundle savedInstanceState) { - SDKInitializer.initialize(getApplicationContext()); - super.onCreate(savedInstanceState); - } - - @Override - protected int getLayoutId() { - return R.layout.fragment_event_location; - } - - @Override - protected void onPause() { - mMapView.onPause(); - super.onPause(); - } - - @Override - protected void onResume() { - mMapView.onResume(); - super.onResume(); - } - - @Override - protected void onDestroy() { - mMapView.onDestroy(); - mSearch.destroy(); - super.onDestroy(); - } - - @Override - public void onGetGeoCodeResult(GeoCodeResult result) { - if (result == null || result.error != SearchResult.ERRORNO.NO_ERROR) { - AppContext.showToast("抱歉,未能找到结果"); - return; - } - mBaiduMap.clear(); - - final LatLng location = result.getLocation(); - - final Marker marker = (Marker) mBaiduMap - .addOverlay(new MarkerOptions() - .position(location) - .icon(BitmapDescriptorFactory - .fromResource(R.drawable.icon_gcoding)) - .draggable(true)); - mBaiduMap.setMapStatus(MapStatusUpdateFactory.newLatLng(result - .getLocation())); - - MapStatusUpdate msu = MapStatusUpdateFactory.zoomTo(14.0f); - mBaiduMap.setMapStatus(msu); - - View view = mInflater.inflate(R.layout.event_spot_pupwindow, null, - false); - - TextView spot = (TextView) view.findViewById(R.id.tv_spot); - spot.setText(mLocation); - OnInfoWindowClickListener listener = new OnInfoWindowClickListener() { - public void onInfoWindowClick() { - onClickInfoWindow(location); - } - }; - InfoWindow mInfoWindow = new InfoWindow( - BitmapDescriptorFactory.fromView(view), location, -80, listener); - - mBaiduMap.showInfoWindow(mInfoWindow); - } - - @Override - public void onGetReverseGeoCodeResult(ReverseGeoCodeResult result) { - if (result == null || result.error != SearchResult.ERRORNO.NO_ERROR) { - return; - } - mBaiduMap.clear(); - mBaiduMap.addOverlay(new MarkerOptions().position(result.getLocation()) - .icon(BitmapDescriptorFactory - .fromResource(R.drawable.icon_gcoding))); - mBaiduMap.setMapStatus(MapStatusUpdateFactory.newLatLng(result - .getLocation())); - } - - @Override - public void onClick(View v) { - - } - - private void onClickInfoWindow(final LatLng location) { - // 开启定位图层 - mBaiduMap.setMyLocationEnabled(true); - // 定位初始化 - final LocationClient mLocClient = new LocationClient( - EventLocationActivity.this); - mLocClient.registerLocationListener(new BDLocationListener() { - - @Override - public void onReceivePoi(BDLocation arg0) { - - } - - @Override - public void onReceiveLocation(BDLocation arg0) { - mLocClient.stop(); - LatLng start = new LatLng(arg0.getLatitude(), arg0 - .getLongitude()); - startNavi(start, location); - } - }); - LocationClientOption option = new LocationClientOption(); - option.setOpenGps(true);// 打开gps - option.setCoorType("bd09ll"); // 设置坐标类型 - option.setScanSpan(1000); - mLocClient.setLocOption(option); - mLocClient.start(); - } - - /** - * 开始导航 - * - */ - private void startNavi(LatLng pt1, LatLng pt2) { - // 构建 导航参数 - NaviPara para = new NaviPara(); - para.startPoint = pt1; - para.endPoint = pt2; - try { - BaiduMapNavigation.openBaiduMapNavi(para, this); - } catch (BaiduMapAppNotSupportNaviException e) { - AppContext.showToast("抱歉,你的百度地图暂不支持打开导航"); - } - } - - @Override - public void initView() { - // 地图初始化 - mMapView = (MapView) findViewById(R.id.bmapView); - mBaiduMap = mMapView.getMap(); - - // 初始化搜索模块,注册事件监听 - mSearch = GeoCoder.newInstance(); - mSearch.setOnGetGeoCodeResultListener(this); - - Intent intent = getIntent(); - - mCity = intent.getStringExtra("city"); - - mLocation = intent.getStringExtra("location"); - - // Geo搜索 - mSearch.geocode(new GeoCodeOption().city(mCity).address(mLocation)); - } - - @Override - public void initData() { - - } -} \ No newline at end of file diff --git a/app/src/main/java/net/oschina/app/ui/FindUserActivity.java b/app/src/main/java/net/oschina/app/ui/FindUserActivity.java deleted file mode 100644 index eb172d3dc3f9397b63d9263c961af00854feed22..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/ui/FindUserActivity.java +++ /dev/null @@ -1,157 +0,0 @@ -package net.oschina.app.ui; - -import android.graphics.Color; -import android.support.v7.widget.SearchView; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.widget.AdapterView; -import android.widget.ListView; -import android.widget.TextView; - -import com.loopj.android.http.AsyncHttpResponseHandler; - -import net.oschina.app.R; -import net.oschina.app.adapter.FindUserAdapter; -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.base.BaseActivity; -import net.oschina.app.bean.FindUserList; -import net.oschina.app.bean.ListEntity; -import net.oschina.app.bean.User; -import net.oschina.app.ui.empty.EmptyLayout; -import net.oschina.app.util.StringUtils; -import net.oschina.app.util.UIHelper; -import net.oschina.app.util.XmlUtils; - -import cz.msebera.android.httpclient.Header; - -import java.io.ByteArrayInputStream; -import java.util.List; - -import butterknife.InjectView; - -/** - * Created by 火蚁 on 15/5/27. - */ -public class FindUserActivity extends BaseActivity implements AdapterView.OnItemClickListener { - - private SearchView mSearchView; - - @InjectView(R.id.lv_list) - ListView mListView; - - @InjectView(R.id.error_layout) - EmptyLayout mErrorLayout; - - private FindUserAdapter mAdapter; - - private AsyncHttpResponseHandler mHandle = new AsyncHttpResponseHandler() { - - @Override - public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { - mErrorLayout.setErrorType(EmptyLayout.HIDE_LAYOUT); - ListEntity list = XmlUtils.toBean(FindUserList.class, - new ByteArrayInputStream(arg2)); - executeOnLoadDataSuccess(list.getList()); - mActionBar.setTitle("找人 "); - } - - @Override - public void onFailure(int arg0, Header[] arg1, byte[] arg2, - Throwable arg3) { - mErrorLayout.setErrorType(EmptyLayout.NETWORK_ERROR); - } - }; - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.search_menu, menu); - MenuItem search = menu.findItem(R.id.search_content); - mSearchView = (SearchView) search.getActionView(); - mSearchView.setIconifiedByDefault(false); - setSearch(); - return super.onCreateOptionsMenu(menu); - } - - private void setSearch() { - mSearchView.setQueryHint("输入用户昵称"); - TextView textView = (TextView) mSearchView - .findViewById(R.id.search_src_text); - textView.setTextColor(Color.WHITE); - - mSearchView - .setOnQueryTextListener(new SearchView.OnQueryTextListener() { - - @Override - public boolean onQueryTextSubmit(String arg0) { - return false; - } - - @Override - public boolean onQueryTextChange(String arg0) { - search(arg0); - return false; - } - }); - } - - private void search(String nickName) { - if (nickName == null || StringUtils.isEmpty(nickName)) { - return; - } - mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING); - mListView.setVisibility(View.GONE); - OSChinaApi.findUser(nickName, mHandle); - } - - @Override - protected int getLayoutId() { - return R.layout.fragment_find_user; - } - - @Override - protected boolean hasBackButton() { - return true; - } - - @Override - public void initView() { - mAdapter = new FindUserAdapter(); - mListView.setAdapter(mAdapter); - mListView.setOnItemClickListener(this); - - mErrorLayout.setOnLayoutClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - search(mSearchView.getQuery().toString()); - } - }); - } - - @Override - public void initData() { - - } - - @Override - public void onClick(View view) { - - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, - long id) { - User user = mAdapter.getItem(position); - if (user != null) { - UIHelper.showUserCenter(FindUserActivity.this, user.getId(), - user.getName()); - } - } - - private void executeOnLoadDataSuccess(List data) { - mAdapter.clear(); - mAdapter.addData(data); - mListView.setVisibility(View.VISIBLE); - } -} diff --git a/app/src/main/java/net/oschina/app/ui/ImagePreviewActivity.java b/app/src/main/java/net/oschina/app/ui/ImagePreviewActivity.java deleted file mode 100644 index 073c6ef4b07a8e4c158c6a0d35ded79e2a43a591..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/ui/ImagePreviewActivity.java +++ /dev/null @@ -1,272 +0,0 @@ -package net.oschina.app.ui; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.content.Intent; -import android.graphics.drawable.ColorDrawable; -import android.os.Bundle; -import android.support.v4.view.ViewPager.OnPageChangeListener; -import android.support.v7.app.ActionBar; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.ProgressBar; -import android.widget.TextView; - -import net.oschina.app.AppConfig; -import net.oschina.app.AppContext; -import net.oschina.app.R; -import net.oschina.app.adapter.RecyclingPagerAdapter; -import net.oschina.app.base.BaseActivity; -import net.oschina.app.bean.SimpleBackPage; -import net.oschina.app.fragment.TweetPubFragment; -import net.oschina.app.ui.dialog.ImageMenuDialog; -import net.oschina.app.ui.dialog.ImageMenuDialog.OnMenuClickListener; -import net.oschina.app.util.TDevice; -import net.oschina.app.util.UIHelper; -import net.oschina.app.widget.HackyViewPager; - -import org.kymjs.kjframe.Core; -import org.kymjs.kjframe.bitmap.BitmapCallBack; - -import uk.co.senab.photoview.PhotoView; -import uk.co.senab.photoview.PhotoViewAttacher; - -/** - * 图片预览界面 - * - * @author kymjs - */ -public class ImagePreviewActivity extends BaseActivity implements - OnPageChangeListener { - - public static final String BUNDLE_KEY_IMAGES = "bundle_key_images"; - private static final String BUNDLE_KEY_INDEX = "bundle_key_index"; - private SamplePagerAdapter mAdapter; - private TextView mTvImgIndex; - private int mCurrentPostion = 0; - private String[] mImageUrls; - - public static void showImagePrivew(Context context, int index, - String[] images) { - Intent intent = new Intent(context, ImagePreviewActivity.class); - - intent.putExtra(BUNDLE_KEY_IMAGES, images); - intent.putExtra(BUNDLE_KEY_INDEX, index); - context.startActivity(intent); - } - - @Override - protected boolean hasActionBar() { - ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.hide(); - } - return true; - } - - @Override - protected int getLayoutId() { - return R.layout.activity_image_preview; - } - - @Override - protected void init(Bundle savedInstanceState) { - super.init(savedInstanceState); - HackyViewPager mViewPager = (HackyViewPager) findViewById(R.id.view_pager); - - mImageUrls = getIntent().getStringArrayExtra(BUNDLE_KEY_IMAGES); - int index = getIntent().getIntExtra(BUNDLE_KEY_INDEX, 0); - - mAdapter = new SamplePagerAdapter(mImageUrls); - mViewPager.setAdapter(mAdapter); - mViewPager.addOnPageChangeListener(this); - mViewPager.setCurrentItem(index); - - mTvImgIndex = (TextView) findViewById(R.id.tv_img_index); - ImageView mIvMore = (ImageView) findViewById(R.id.iv_more); - mIvMore.setOnClickListener(this); - - onPageSelected(index); - } - - @Override - public void onClick(View v) { - int id = v.getId(); - switch (id) { - case R.id.iv_more: - showOptionMenu(); - break; - default: - break; - } - } - - @Override - public void initView() { - } - - @Override - public void initData() { - } - - private void showOptionMenu() { - final ImageMenuDialog dialog = new ImageMenuDialog(this); - dialog.show(); - dialog.setCancelable(true); - dialog.setOnMenuClickListener(new OnMenuClickListener() { - @Override - public void onClick(TextView menuItem) { - if (menuItem.getId() == R.id.menu1) { - saveImg(); - } else if (menuItem.getId() == R.id.menu2) { - sendTweet(); - } else if (menuItem.getId() == R.id.menu3) { - copyUrl(); - } - dialog.dismiss(); - } - }); - } - - /** - * 复制链接 - */ - private void copyUrl() { - String content = null; - if (mAdapter != null && mAdapter.getCount() > 0) { - content = mAdapter.getItem(mCurrentPostion); - TDevice.copyTextToBoard(content); - AppContext.showToastShort("已复制到剪贴板"); - } - } - - /** - * 发送到动弹 - */ - private void sendTweet() { - if (mAdapter != null && mAdapter.getCount() > 0) { - String imgUrl = mAdapter.getItem(mCurrentPostion); - Bundle bundle = new Bundle(); - bundle.putString(TweetPubFragment.FROM_IMAGEPAGE_KEY, imgUrl); - UIHelper.showSimpleBack(this, SimpleBackPage.TWEET_PUB, bundle); - finish(); - } - } - - /** - * 保存图片 - */ - private void saveImg() { - if (mAdapter != null && mAdapter.getCount() > 0) { - final String imgUrl = mAdapter.getItem(mCurrentPostion); - final String filePath = AppConfig.DEFAULT_SAVE_IMAGE_PATH - + getFileName(imgUrl); - Core.getKJBitmap().saveImage(this, imgUrl, filePath); - AppContext.showToastShort(getString(R.string.tip_save_image_suc, - filePath)); - } else { - AppContext.showToastShort(R.string.tip_save_image_faile); - } - } - - private String getFileName(String imgUrl) { - int index = imgUrl.lastIndexOf('/') + 1; - if (index == -1) { - return System.currentTimeMillis() + ".jpeg"; - } - return imgUrl.substring(index); - } - - @Override - public void onPageScrollStateChanged(int arg0) { - } - - @Override - public void onPageScrolled(int arg0, float arg1, int arg2) { - } - - @Override - public void onPageSelected(int idx) { - mCurrentPostion = idx; - if (mImageUrls != null && mImageUrls.length > 1) { - if (mTvImgIndex != null) { - mTvImgIndex.setText(String.format("%d/%d", mCurrentPostion + 1, mImageUrls.length)); - } - } - } - - class SamplePagerAdapter extends RecyclingPagerAdapter { - - private String[] images = new String[]{}; - - SamplePagerAdapter(String[] images) { - this.images = images; - } - - public String getItem(int position) { - return images[position]; - } - - @Override - public int getCount() { - return images.length; - } - - @Override - @SuppressLint("InflateParams") - public View getView(int position, View convertView, ViewGroup container) { - ViewHolder vh = null; - if (convertView == null) { - convertView = LayoutInflater.from(container.getContext()) - .inflate(R.layout.image_preview_item, null); - vh = new ViewHolder(convertView); - convertView.setTag(vh); - } else { - vh = (ViewHolder) convertView.getTag(); - } - - final ProgressBar bar = vh.progress; - new Core.Builder().view(vh.image).url(images[position]) - .loadBitmap(new ColorDrawable(0x000000)) - .errorBitmap(new ColorDrawable(0x000000)) - .size(0, 0) - .bitmapCallBack(new BitmapCallBack() { - @Override - public void onPreLoad() { - bar.setVisibility(View.VISIBLE); - } - - @Override - public void onFinish() { - bar.setVisibility(View.GONE); - } - - @Override - public void onFailure(Exception arg0) { - AppContext.showToast(R.string.tip_load_image_faile); - } - }).doTask(); - vh.attacher.setOnPhotoTapListener(new PhotoViewAttacher.OnPhotoTapListener() { - @Override - public void onPhotoTap(View view, float v, float v1) { - ImagePreviewActivity.this.finish(); - } - }); - return convertView; - } - } - - static class ViewHolder { - PhotoView image; - ProgressBar progress; - PhotoViewAttacher attacher; - - ViewHolder(View view) { - image = (PhotoView) view.findViewById(R.id.photoview); - progress = (ProgressBar) view.findViewById(R.id.progress); - attacher = new PhotoViewAttacher(image); - } - } -} diff --git a/app/src/main/java/net/oschina/app/ui/LoginAccountBindOpenIdActivity.java b/app/src/main/java/net/oschina/app/ui/LoginAccountBindOpenIdActivity.java deleted file mode 100644 index d9d301e31d7a09b5c2225e50a0ebdfd70e81af6c..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/ui/LoginAccountBindOpenIdActivity.java +++ /dev/null @@ -1,132 +0,0 @@ -package net.oschina.app.ui; - -import android.app.ProgressDialog; -import android.content.Intent; -import android.os.Bundle; -import android.view.View; -import android.widget.EditText; - -import com.loopj.android.http.AsyncHttpResponseHandler; - -import net.oschina.app.R; -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.base.BaseActivity; -import net.oschina.app.bean.LoginUserBean; -import net.oschina.app.util.DialogHelp; -import net.oschina.app.util.XmlUtils; - -import cz.msebera.android.httpclient.Header; -import butterknife.InjectView; -import butterknife.OnClick; - -/** - * 第三方登陆账号绑定操作 - * Created by zhangdeyi on 15/7/21. - */ -public class LoginAccountBindOpenIdActivity extends BaseActivity { - - @InjectView(R.id.et_username) - EditText etUsername; - @InjectView(R.id.et_password) - EditText etPassword; - - private String catalog; - private String openIdInfo; - - @Override - protected boolean hasBackButton() { - return true; - } - - @Override - protected int getActionBarTitle() { - return R.string.login; - } - - @Override - protected int getLayoutId() { - return R.layout.activity_account_bind_openid; - } - - @Override - public void initView() { - - } - - @Override - public void initData() { - Intent intent = getIntent(); - if (intent != null) { - catalog = intent.getStringExtra(LoginBindActivityChooseActivity.BUNDLE_KEY_CATALOG); - openIdInfo = intent.getStringExtra(LoginBindActivityChooseActivity.BUNDLE_KEY_OPENIDINFO); - } - } - - @OnClick(R.id.bt_bind) - @Override - public void onClick(View v) { - switch (v.getId()) { - case R.id.bt_bind: - toBind(); - break; - } - } - - private void toBind() { - if (checkInputInof()) { - return; - } - - String username = etUsername.getText().toString(); - String password = etPassword.getText().toString(); - final ProgressDialog waitDialog = DialogHelp.getWaitDialog(this, "加载中..."); - OSChinaApi.bind_openid(catalog, openIdInfo, username, password, new AsyncHttpResponseHandler() { - @Override - public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { - LoginUserBean loginUserBean = XmlUtils.toBean(LoginUserBean.class, responseBody); - if (loginUserBean != null && loginUserBean.getResult().OK()) { - Intent data = new Intent(); - Bundle bundle = new Bundle(); - bundle.putSerializable(LoginActivity.BUNDLE_KEY_LOGINBEAN, loginUserBean); - data.putExtras(bundle); - setResult(RESULT_OK, data); - finish(); - } else { - DialogHelp.getMessageDialog(LoginAccountBindOpenIdActivity.this, loginUserBean.getResult().getErrorMessage()).show(); - } - } - - @Override - public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { - - } - - @Override - public void onStart() { - super.onStart(); - waitDialog.show(); - } - - @Override - public void onFinish() { - super.onFinish(); - waitDialog.dismiss(); - } - }); - } - - private boolean checkInputInof() { - if (etUsername.length() == 0) { - etUsername.setError("请输入用户名"); - etUsername.requestFocus(); - return true; - } - - if (etPassword.length() == 0) { - etPassword.setError("请输入密码"); - etPassword.requestFocus(); - return true; - } - return false; - } -} diff --git a/app/src/main/java/net/oschina/app/ui/LoginActivity.java b/app/src/main/java/net/oschina/app/ui/LoginActivity.java deleted file mode 100644 index 9e96a6bf3426059e393f52d7ca2df14a3155982c..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/ui/LoginActivity.java +++ /dev/null @@ -1,420 +0,0 @@ -package net.oschina.app.ui; - -import net.oschina.app.AppConfig; -import net.oschina.app.AppContext; -import net.oschina.app.R; -import net.oschina.app.api.ApiHttpClient; -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.base.BaseActivity; -import net.oschina.app.bean.Constants; -import net.oschina.app.bean.LoginUserBean; -import net.oschina.app.bean.OpenIdCatalog; -import net.oschina.app.util.CyptoUtils; -import net.oschina.app.util.DialogHelp; -import net.oschina.app.util.TDevice; -import net.oschina.app.util.TLog; -import net.oschina.app.util.XmlUtils; - -import cz.msebera.android.httpclient.Header; -import org.kymjs.kjframe.http.HttpConfig; - -import android.app.ProgressDialog; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Bundle; -import android.text.TextUtils; -import android.view.View; -import android.widget.EditText; - -import butterknife.InjectView; -import butterknife.OnClick; -import cz.msebera.android.httpclient.client.CookieStore; -import cz.msebera.android.httpclient.client.protocol.ClientContext; -import cz.msebera.android.httpclient.cookie.Cookie; -import cz.msebera.android.httpclient.protocol.HttpContext; - -import com.loopj.android.http.AsyncHttpClient; -import com.loopj.android.http.AsyncHttpResponseHandler; -import com.tencent.mm.sdk.modelmsg.SendAuth; -import com.tencent.mm.sdk.openapi.IWXAPI; -import com.tencent.mm.sdk.openapi.WXAPIFactory; -import com.tencent.tauth.IUiListener; -import com.tencent.tauth.Tencent; -import com.tencent.tauth.UiError; -import com.umeng.socialize.bean.SHARE_MEDIA; -import com.umeng.socialize.controller.UMServiceFactory; -import com.umeng.socialize.controller.UMSocialService; -import com.umeng.socialize.controller.listener.SocializeListeners; -import com.umeng.socialize.exception.SocializeException; -import com.umeng.socialize.sso.SinaSsoHandler; - -import java.util.Map; -import java.util.Set; - -/** - * 用户登录界面 - * - * @author kymjs (http://www.kymjs.com/) - */ -public class LoginActivity extends BaseActivity implements IUiListener { - - public static final int REQUEST_CODE_INIT = 0; - private static final String BUNDLE_KEY_REQUEST_CODE = "BUNDLE_KEY_REQUEST_CODE"; - protected static final String TAG = LoginActivity.class.getSimpleName(); - - @InjectView(R.id.et_username) - EditText mEtUserName; - - @InjectView(R.id.et_password) - EditText mEtPassword; - - private final int requestCode = REQUEST_CODE_INIT; - private String mUserName = ""; - private String mPassword = ""; - - @Override - protected int getLayoutId() { - return R.layout.activity_login; - } - - @Override - public void initView() { - - } - - @Override - protected boolean hasBackButton() { - return true; - } - - @Override - protected int getActionBarTitle() { - return R.string.login; - } - - @Override - @OnClick({R.id.btn_login, R.id.iv_qq_login, R.id.iv_wx_login, R.id.iv_sina_login}) - public void onClick(View v) { - - int id = v.getId(); - switch (id) { - case R.id.btn_login: - handleLogin(); - break; - case R.id.iv_qq_login: - qqLogin(); - break; - case R.id.iv_wx_login: - wxLogin(); - break; - case R.id.iv_sina_login: - sinaLogin(); - break; - default: - break; - } - } - - private void handleLogin() { - - if (prepareForLogin()) { - return; - } - - // if the data has ready - mUserName = mEtUserName.getText().toString(); - mPassword = mEtPassword.getText().toString(); - - showWaitDialog(R.string.progress_login); - OSChinaApi.login(mUserName, mPassword, mHandler); - } - - private final AsyncHttpResponseHandler mHandler = new AsyncHttpResponseHandler() { - - @Override - public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { - LoginUserBean loginUserBean = XmlUtils.toBean(LoginUserBean.class, arg2); - if (loginUserBean != null) { - handleLoginBean(loginUserBean); - } - } - - @Override - public void onFailure(int arg0, Header[] arg1, byte[] arg2, - Throwable arg3) { - AppContext.showToast("网络出错" + arg0); - } - - @Override - public void onFinish() { - super.onFinish(); - hideWaitDialog(); - } - }; - - private void handleLoginSuccess() { - Intent data = new Intent(); - data.putExtra(BUNDLE_KEY_REQUEST_CODE, requestCode); - setResult(RESULT_OK, data); - this.sendBroadcast(new Intent(Constants.INTENT_ACTION_USER_CHANGE)); - finish(); - } - - private boolean prepareForLogin() { - if (!TDevice.hasInternet()) { - AppContext.showToastShort(R.string.tip_no_internet); - return true; - } - if (mEtUserName.length() == 0) { - mEtUserName.setError("请输入邮箱/用户名"); - mEtUserName.requestFocus(); - return true; - } - - if (mEtPassword.length() == 0) { - mEtPassword.setError("请输入密码"); - mEtPassword.requestFocus(); - return true; - } - - return false; - } - - @Override - public void initData() { - - mEtUserName.setText(AppContext.getInstance() - .getProperty("user.account")); - mEtPassword.setText(CyptoUtils.decode("oschinaApp", AppContext - .getInstance().getProperty("user.pwd"))); - } - - /** - * QQ登陆 - */ - private void qqLogin() { - Tencent mTencent = Tencent.createInstance(AppConfig.APP_QQ_KEY, - this); - mTencent.login(this, "all", this); - } - - BroadcastReceiver receiver; - /** - * 微信登陆 - */ - private void wxLogin() { - IWXAPI api = WXAPIFactory.createWXAPI(this, Constants.WEICHAT_APPID, false); - api.registerApp(Constants.WEICHAT_APPID); - - if (!api.isWXAppInstalled()) { - AppContext.showToast("手机中没有安装微信客户端"); - return; - } - // 唤起微信登录授权 - final SendAuth.Req req = new SendAuth.Req(); - req.scope = "snsapi_userinfo"; - req.state = "wechat_login"; - api.sendReq(req); - // 注册一个广播,监听微信的获取openid返回(类:WXEntryActivity中) - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(OpenIdCatalog.WECHAT); - receiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (intent != null) { - String openid_info = intent.getStringExtra(LoginBindActivityChooseActivity.BUNDLE_KEY_OPENIDINFO); - openIdLogin(OpenIdCatalog.WECHAT, openid_info); - // 注销这个监听广播 - if (receiver != null) { - unregisterReceiver(receiver); - } - } - } - }; - - registerReceiver(receiver, intentFilter); - } - - /** - * 新浪登录 - */ - private void sinaLogin() { - final UMSocialService mController = UMServiceFactory.getUMSocialService("com.umeng.login"); - SinaSsoHandler sinaSsoHandler = new SinaSsoHandler(); - mController.getConfig().setSsoHandler(sinaSsoHandler); - mController.doOauthVerify(this, SHARE_MEDIA.SINA, - new SocializeListeners.UMAuthListener() { - - @Override - public void onStart(SHARE_MEDIA arg0) { - } - - @Override - public void onError(SocializeException arg0, - SHARE_MEDIA arg1) { - AppContext.showToast("新浪授权失败"); - } - - @Override - public void onComplete(Bundle value, SHARE_MEDIA arg1) { - if (value != null && !TextUtils.isEmpty(value.getString("uid"))) { - // 获取平台信息 - mController.getPlatformInfo(LoginActivity.this, SHARE_MEDIA.SINA, new SocializeListeners.UMDataListener() { - @Override - public void onStart() { - - } - - @Override - public void onComplete(int i, Map map) { - if (i == 200 && map != null) { - StringBuilder sb = new StringBuilder("{"); - Set keys = map.keySet(); - int index = 0; - for (String key : keys) { - index++; - String jsonKey = key; - if (jsonKey.equals("uid")) { - jsonKey = "openid"; - } - sb.append(String.format("\"%s\":\"%s\"", jsonKey, map.get(key).toString())); - if (index != map.size()) { - sb.append(","); - } - } - sb.append("}"); - openIdLogin(OpenIdCatalog.WEIBO, sb.toString()); - } else { - AppContext.showToast("发生错误:" + i); - } - } - }); - } else { - AppContext.showToast("授权失败"); - } - } - - @Override - public void onCancel(SHARE_MEDIA arg0) { - AppContext.showToast("已取消新浪登陆"); - } - }); - } - - // 获取到QQ授权登陆的信息 - @Override - public void onComplete(Object o) { - openIdLogin(OpenIdCatalog.QQ, o.toString()); - } - - @Override - public void onError(UiError uiError) { - - } - - @Override - public void onCancel() { - - } - - /*** - * - * @param catalog 第三方登录的类别 - * @param openIdInfo 第三方的信息 - */ - private void openIdLogin(final String catalog, final String openIdInfo) { - final ProgressDialog waitDialog = DialogHelp.getWaitDialog(this, "登陆中..."); - OSChinaApi.open_login(catalog, openIdInfo, new AsyncHttpResponseHandler() { - @Override - public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { - LoginUserBean loginUserBean = XmlUtils.toBean(LoginUserBean.class, responseBody); - if (loginUserBean.getResult().OK()) { - handleLoginBean(loginUserBean); - } else { - // 前往绑定或者注册操作 - Intent intent = new Intent(LoginActivity.this, LoginBindActivityChooseActivity.class); - intent.putExtra(LoginBindActivityChooseActivity.BUNDLE_KEY_CATALOG, catalog); - intent.putExtra(LoginBindActivityChooseActivity.BUNDLE_KEY_OPENIDINFO, openIdInfo); - startActivityForResult(intent, REQUEST_CODE_OPENID); - } - } - - @Override - public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { - AppContext.showToast("网络出错" + statusCode); - } - - @Override - public void onStart() { - super.onStart(); - waitDialog.show(); - } - - @Override - public void onFinish() { - super.onFinish(); - waitDialog.dismiss(); - } - }); - } - - public static final int REQUEST_CODE_OPENID = 1000; - // 登陆实体类 - public static final String BUNDLE_KEY_LOGINBEAN = "bundle_key_loginbean"; - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - switch (requestCode) { - case REQUEST_CODE_OPENID: - if (data == null) { - return; - } - LoginUserBean loginUserBean = (LoginUserBean) data.getSerializableExtra(BUNDLE_KEY_LOGINBEAN); - if (loginUserBean != null) { - handleLoginBean(loginUserBean); - } - break; - default: - - break; - } - } - - // 处理loginBean - private void handleLoginBean(LoginUserBean loginUserBean) { - if (loginUserBean.getResult().OK()) { - AsyncHttpClient client = ApiHttpClient.getHttpClient(); - HttpContext httpContext = client.getHttpContext(); - CookieStore cookies = (CookieStore) httpContext - .getAttribute(ClientContext.COOKIE_STORE); - if (cookies != null) { - String tmpcookies = ""; - for (Cookie c : cookies.getCookies()) { - TLog.log(TAG, - "cookie:" + c.getName() + " " + c.getValue()); - tmpcookies += (c.getName() + "=" + c.getValue()) + ";"; - } - TLog.log(TAG, "cookies:" + tmpcookies); - AppContext.getInstance().setProperty(AppConfig.CONF_COOKIE, - tmpcookies); - ApiHttpClient.setCookie(ApiHttpClient.getCookie(AppContext - .getInstance())); - HttpConfig.sCookie = tmpcookies; - } - // 保存登录信息 - loginUserBean.getUser().setAccount(mUserName); - loginUserBean.getUser().setPwd(mPassword); - loginUserBean.getUser().setRememberMe(true); - AppContext.getInstance().saveUserInfo(loginUserBean.getUser()); - hideWaitDialog(); - handleLoginSuccess(); - - } else { - AppContext.getInstance().cleanLoginInfo(); - AppContext.showToast(loginUserBean.getResult().getErrorMessage()); - } - } -} diff --git a/app/src/main/java/net/oschina/app/ui/LoginBindActivityChooseActivity.java b/app/src/main/java/net/oschina/app/ui/LoginBindActivityChooseActivity.java deleted file mode 100644 index eb68f7e5e3125ee35c24a383d540cd30d24e386e..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/ui/LoginBindActivityChooseActivity.java +++ /dev/null @@ -1,157 +0,0 @@ -package net.oschina.app.ui; - -import android.app.ProgressDialog; -import android.content.Intent; -import android.os.Bundle; -import android.view.View; -import android.widget.TextView; - -import com.loopj.android.http.AsyncHttpResponseHandler; - -import net.oschina.app.R; -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.base.BaseActivity; -import net.oschina.app.bean.LoginUserBean; -import net.oschina.app.bean.OpenIdCatalog; -import net.oschina.app.util.DialogHelp; -import net.oschina.app.util.XmlUtils; - -import cz.msebera.android.httpclient.Header; - -import butterknife.InjectView; -import butterknife.OnClick; - -/** - * 账号绑定、账号注册 - * Created by zhangdeyi on 15/7/17. - */ -public class LoginBindActivityChooseActivity extends BaseActivity { - - public static final String BUNDLE_KEY_CATALOG = "bundle_key_catalog"; - public static final String BUNDLE_KEY_OPENIDINFO = "bundle_key_openid_info"; - - private String catalog; - private String openIdInfo; - - @Override - protected boolean hasBackButton() { - return true; - } - - @Override - protected int getLayoutId() { - return R.layout.activity_login_bind_choose; - } - - @Override - public void initView() { - - } - - @Override - public void initData() { - Intent intent = getIntent(); - if (intent != null) { - catalog = intent.getStringExtra(BUNDLE_KEY_CATALOG); - openIdInfo = intent.getStringExtra(BUNDLE_KEY_OPENIDINFO); - initCatalogText(); - } - } - - @InjectView(R.id.tv_openid_tip) - TextView tvOpenIdTip; - private void initCatalogText() { - if (catalog.equals(OpenIdCatalog.QQ)) { - tvOpenIdTip.setText("你好,QQ用户"); - } else if (catalog.equals(OpenIdCatalog.WECHAT)) { - tvOpenIdTip.setText("你好,微信用户"); - } else if (catalog.equals(OpenIdCatalog.WEIBO)) { - tvOpenIdTip.setText("你好,新浪用户"); - } else if (catalog.equals(OpenIdCatalog.GITHUB)) { - tvOpenIdTip.setText("你好,Github用户"); - } - } - - @Override - @OnClick({R.id.bt_bind, R.id.bt_reg}) - public void onClick(View v) { - switch (v.getId()) { - case R.id.bt_bind: - toBind(); - break; - case R.id.bt_reg: - to_reg(); - break; - } - } - - private void toBind() { - Intent intent = new Intent(this, LoginAccountBindOpenIdActivity.class); - intent.putExtra(BUNDLE_KEY_CATALOG, catalog); - intent.putExtra(BUNDLE_KEY_OPENIDINFO, openIdInfo); - startActivityForResult(intent, LoginActivity.REQUEST_CODE_OPENID); - } - - private void to_reg() { - final ProgressDialog waitDialog = DialogHelp.getWaitDialog(this, "加载中..."); - OSChinaApi.openid_reg(catalog, openIdInfo, new AsyncHttpResponseHandler() { - @Override - public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { - try { - LoginUserBean loginUserBean = XmlUtils.toBean(LoginUserBean.class, responseBody); - if (loginUserBean != null && loginUserBean.getResult().OK()) { - backLogin(loginUserBean); - } else { - if (loginUserBean.getResult() != null) { - DialogHelp.getMessageDialog(LoginBindActivityChooseActivity.this, loginUserBean.getResult().getErrorMessage()).show(); - } else { - DialogHelp.getMessageDialog(LoginBindActivityChooseActivity.this, "使用第三方注册失败").show(); - } - } - } catch (Exception e) { - DialogHelp.getMessageDialog(LoginBindActivityChooseActivity.this, "使用第三方注册失败").show(); - } - } - - @Override - public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { - DialogHelp.getMessageDialog(LoginBindActivityChooseActivity.this, "网络出错" + statusCode).show(); - } - - @Override - public void onStart() { - super.onStart(); - waitDialog.show(); - } - - @Override - public void onFinish() { - super.onFinish(); - waitDialog.dismiss(); - } - }); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - switch (requestCode) { - case LoginActivity.REQUEST_CODE_OPENID: - if (data == null) { - return; - } - LoginUserBean loginUserBean = (LoginUserBean) data.getSerializableExtra(LoginActivity.BUNDLE_KEY_LOGINBEAN); - backLogin(loginUserBean); - break; - } - } - - private void backLogin(LoginUserBean loginUserBean) { - Intent data = new Intent(); - Bundle bundle = new Bundle(); - bundle.putSerializable(LoginActivity.BUNDLE_KEY_LOGINBEAN, loginUserBean); - data.putExtras(bundle); - setResult(RESULT_OK, data); - finish(); - } -} diff --git a/app/src/main/java/net/oschina/app/ui/MainActivity.java b/app/src/main/java/net/oschina/app/ui/MainActivity.java deleted file mode 100644 index 14d977b6d9a27d59b5cff9ba29b283def2df6b76..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/ui/MainActivity.java +++ /dev/null @@ -1,407 +0,0 @@ -package net.oschina.app.ui; - -import android.annotation.SuppressLint; -import android.annotation.TargetApi; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.graphics.drawable.Drawable; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.support.v4.app.Fragment; -import android.support.v4.widget.DrawerLayout; -import android.support.v7.app.ActionBar; -import android.support.v7.app.ActionBarActivity; -import android.util.TypedValue; -import android.view.Gravity; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.MotionEvent; -import android.view.View; -import android.view.View.OnTouchListener; -import android.widget.TabHost.OnTabChangeListener; -import android.widget.TabHost.TabContentFactory; -import android.widget.TabHost.TabSpec; -import android.widget.TextView; - -import com.networkbench.agent.impl.NBSAppAgent; - -import net.oschina.app.AppConfig; -import net.oschina.app.AppContext; -import net.oschina.app.AppManager; -import net.oschina.app.R; -import net.oschina.app.bean.Constants; -import net.oschina.app.bean.Notice; -import net.oschina.app.bean.SimpleBackPage; -import net.oschina.app.cache.DataCleanManager; -import net.oschina.app.fragment.MyInformationFragment; -import net.oschina.app.interf.BaseViewInterface; -import net.oschina.app.interf.OnTabReselectListener; -import net.oschina.app.service.NoticeUtils; -import net.oschina.app.util.UIHelper; -import net.oschina.app.util.UpdateManager; -import net.oschina.app.widget.BadgeView; -import net.oschina.app.widget.MyFragmentTabHost; - -import butterknife.ButterKnife; -import butterknife.InjectView; - -@SuppressLint("InflateParams") -@TargetApi(Build.VERSION_CODES.HONEYCOMB) -public class MainActivity extends ActionBarActivity implements - NavigationDrawerFragment.NavigationDrawerCallbacks, - OnTabChangeListener, BaseViewInterface, View.OnClickListener, - OnTouchListener { - - private DoubleClickExitHelper mDoubleClickExit; - - /** - * Fragment managing the behaviors, interactions and presentation of the - * navigation drawer. - */ - private NavigationDrawerFragment mNavigationDrawerFragment; - - @InjectView(android.R.id.tabhost) - public MyFragmentTabHost mTabHost; - - private BadgeView mBvNotice; - - public static Notice mNotice; - - private BroadcastReceiver mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(Constants.INTENT_ACTION_NOTICE)) { - mNotice = (Notice) intent.getSerializableExtra("notice_bean"); - int atmeCount = mNotice.getAtmeCount();// @我 - int msgCount = mNotice.getMsgCount();// 留言 - int reviewCount = mNotice.getReviewCount();// 评论 - int newFansCount = mNotice.getNewFansCount();// 新粉丝 - int newLikeCount = mNotice.getNewLikeCount();// 收到赞 - int activeCount = atmeCount + reviewCount + msgCount - + newFansCount + newLikeCount; - - Fragment fragment = getCurrentFragment(); - if (fragment instanceof MyInformationFragment) { - ((MyInformationFragment) fragment).setNotice(); - } else { - if (activeCount > 0) { - mBvNotice.setText(activeCount + ""); - mBvNotice.show(); - } else { - mBvNotice.hide(); - mNotice = null; - } - } - } else if (intent.getAction() - .equals(Constants.INTENT_ACTION_LOGOUT)) { - mBvNotice.hide(); - mNotice = null; - } - } - }; - - /** - * Used to store the last screen title. For use in - * {@link #restoreActionBar()}. - */ - private CharSequence mTitle; - - @InjectView(R.id.quick_option_iv) - View mAddBt; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (AppContext.getNightModeSwitch()) { - setTheme(R.style.AppBaseTheme_Night); - } else { - setTheme(R.style.AppBaseTheme_Light); - } - setContentView(R.layout.activity_main); - ButterKnife.inject(this); - initView(); - AppManager.getAppManager().addActivity(this); - - handleIntent(getIntent()); - // 注册听云的检测分析 - NBSAppAgent.setLicenseKey("0ed0cc66c5cb45c0a91c6fa932ca99ac") - .withCrashReportEnabled(true).withLocationServiceEnabled(true) - .start(this); - } - - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - handleIntent(intent); - } - - /** - * 处理传进来的intent - * - * @author 火蚁 2015-1-28 下午3:48:44 - * - * @return void - * @param intent - */ - private void handleIntent(Intent intent) { - if (intent == null) - return; - String action = intent.getAction(); - if (action != null && action.equals(Intent.ACTION_VIEW)) { - UIHelper.showUrlRedirect(this, intent.getDataString()); - } else if (intent.getBooleanExtra("NOTICE", false)) { - notifitcationBarClick(intent); - } - } - - /** - * 从通知栏点击的时候相应 - * - * @param fromWhich - */ - private void notifitcationBarClick(Intent fromWhich) { - if (fromWhich != null) { - boolean fromNoticeBar = fromWhich.getBooleanExtra("NOTICE", false); - if (fromNoticeBar) { - Intent toMyInfor = new Intent(this, SimpleBackActivity.class); - toMyInfor.putExtra(SimpleBackActivity.BUNDLE_KEY_PAGE, - SimpleBackPage.MY_MES.getValue()); - startActivity(toMyInfor); - } - } - } - - @Override - public void initView() { - mDoubleClickExit = new DoubleClickExitHelper(this); - mNavigationDrawerFragment = (NavigationDrawerFragment) getSupportFragmentManager() - .findFragmentById(R.id.navigation_drawer); - mTitle = getTitle(); - - // Set up the drawer. - mNavigationDrawerFragment.setUp(R.id.navigation_drawer, - (DrawerLayout) findViewById(R.id.drawer_layout)); - - mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent); - if (android.os.Build.VERSION.SDK_INT > 10) { - mTabHost.getTabWidget().setShowDividers(0); - } - - initTabs(); - - // 中间按键图片触发 - mAddBt.setOnClickListener(this); - - mTabHost.setCurrentTab(0); - mTabHost.setOnTabChangedListener(this); - - IntentFilter filter = new IntentFilter(Constants.INTENT_ACTION_NOTICE); - filter.addAction(Constants.INTENT_ACTION_LOGOUT); - registerReceiver(mReceiver, filter); - NoticeUtils.bindToService(this); - - if (AppContext.isFristStart()) { - mNavigationDrawerFragment.openDrawerMenu(); - DataCleanManager.cleanInternalCache(AppContext.getInstance()); - AppContext.setFristStart(false); - } - - checkUpdate(); - } - - private void checkUpdate() { - if (!AppContext.get(AppConfig.KEY_CHECK_UPDATE, true)) { - return; - } - Handler handler = new Handler(); - handler.postDelayed(new Runnable() { - - @Override - public void run() { - new UpdateManager(MainActivity.this, false).checkUpdate(); - } - }, 2000); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - NoticeUtils.unbindFromService(this); - unregisterReceiver(mReceiver); - mReceiver = null; - NoticeUtils.tryToShutDown(this); - } - - @Override - public void initData() { - - } - - private void initTabs() { - MainTab[] tabs = MainTab.values(); - final int size = tabs.length; - for (int i = 0; i < size; i++) { - MainTab mainTab = tabs[i]; - TabSpec tab = mTabHost.newTabSpec(getString(mainTab.getResName())); - View indicator = LayoutInflater.from(getApplicationContext()) - .inflate(R.layout.tab_indicator, null); - TextView title = (TextView) indicator.findViewById(R.id.tab_title); - Drawable drawable = this.getResources().getDrawable( - mainTab.getResIcon()); - title.setCompoundDrawablesWithIntrinsicBounds(null, drawable, null, - null); - if (i == 2) { - indicator.setVisibility(View.INVISIBLE); - mTabHost.setNoTabChangedTag(getString(mainTab.getResName())); - } - title.setText(getString(mainTab.getResName())); - tab.setIndicator(indicator); - tab.setContent(new TabContentFactory() { - - @Override - public View createTabContent(String tag) { - return new View(MainActivity.this); - } - }); - mTabHost.addTab(tab, mainTab.getClz(), null); - - if (mainTab.equals(MainTab.ME)) { - View cn = indicator.findViewById(R.id.tab_mes); - mBvNotice = new BadgeView(MainActivity.this, cn); - mBvNotice.setBadgePosition(BadgeView.POSITION_TOP_RIGHT); - mBvNotice.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10); - mBvNotice.setBackgroundResource(R.drawable.notification_bg); - mBvNotice.setGravity(Gravity.CENTER); - } - mTabHost.getTabWidget().getChildAt(i).setOnTouchListener(this); - } - } - - @Override - public void onNavigationDrawerItemSelected(int position) { - // update the main content by replacing fragments - } - - public void restoreActionBar() { - ActionBar actionBar = getSupportActionBar(); - actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); - actionBar.setDisplayShowTitleEnabled(true); - actionBar.setTitle(mTitle); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.main_activity_menu, menu); - if (!mNavigationDrawerFragment.isDrawerOpen()) { - restoreActionBar(); - return true; - } - return super.onCreateOptionsMenu(menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - int id = item.getItemId(); - switch (id) { - case R.id.search: - UIHelper.showSimpleBack(this, SimpleBackPage.SEARCH); - break; - - default: - break; - } - return super.onOptionsItemSelected(item); - } - - @Override - public void onTabChanged(String tabId) { - final int size = mTabHost.getTabWidget().getTabCount(); - for (int i = 0; i < size; i++) { - View v = mTabHost.getTabWidget().getChildAt(i); - if (i == mTabHost.getCurrentTab()) { - v.setSelected(true); - } else { - v.setSelected(false); - } - } - if (tabId.equals(getString(MainTab.ME.getResName()))) { - mBvNotice.setText(""); - mBvNotice.hide(); - } - supportInvalidateOptionsMenu(); - } - - @Override - public void onClick(View v) { - int id = v.getId(); - switch (id) { - // 点击了快速操作按钮 - case R.id.quick_option_iv: - showQuickOption(); - break; - default: - break; - } - } - - // 显示快速操作界面 - private void showQuickOption() { - final QuickOptionDialog dialog = new QuickOptionDialog( - MainActivity.this); - dialog.setCancelable(true); - dialog.setCanceledOnTouchOutside(true); - dialog.show(); - } - - @SuppressLint("ClickableViewAccessibility") - @Override - public boolean onTouch(View v, MotionEvent event) { - super.onTouchEvent(event); - boolean consumed = false; - // use getTabHost().getCurrentTabView to decide if the current tab is - // touched again - if (event.getAction() == MotionEvent.ACTION_DOWN - && v.equals(mTabHost.getCurrentTabView())) { - // use getTabHost().getCurrentView() to get a handle to the view - // which is displayed in the tab - and to get this views context - Fragment currentFragment = getCurrentFragment(); - if (currentFragment != null - && currentFragment instanceof OnTabReselectListener) { - OnTabReselectListener listener = (OnTabReselectListener) currentFragment; - listener.onTabReselect(); - consumed = true; - } - } - return consumed; - } - - private Fragment getCurrentFragment() { - return getSupportFragmentManager().findFragmentByTag( - mTabHost.getCurrentTabTag()); - } - - /** - * 监听返回--是否退出程序 - */ - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_BACK) { - // 是否退出应用 - if (AppContext.get(AppConfig.KEY_DOUBLE_CLICK_EXIT, true)) { - return mDoubleClickExit.onKeyDown(keyCode, event); - } - } - return super.onKeyDown(keyCode, event); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - // TODO Auto-generated method stub - // 当 API Level > 11 调用这个方法可能导致奔溃(android.os.Build.VERSION.SDK_INT > 11) - } -} diff --git a/app/src/main/java/net/oschina/app/ui/MainTab.java b/app/src/main/java/net/oschina/app/ui/MainTab.java deleted file mode 100644 index 55d1035aef88fc6e01bc9f46a44b87a6d7b3aeca..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/ui/MainTab.java +++ /dev/null @@ -1,69 +0,0 @@ -package net.oschina.app.ui; - -import net.oschina.app.R; -import net.oschina.app.fragment.ExploreFragment; -import net.oschina.app.fragment.MyInformationFragment; -import net.oschina.app.viewpagerfragment.NewsViewPagerFragment; -import net.oschina.app.viewpagerfragment.TweetsViewPagerFragment; - -public enum MainTab { - - NEWS(0, R.string.main_tab_name_news, R.drawable.tab_icon_new, - NewsViewPagerFragment.class), - - TWEET(1, R.string.main_tab_name_tweet, R.drawable.tab_icon_tweet, - TweetsViewPagerFragment.class), - - QUICK(2, R.string.main_tab_name_quick, R.drawable.tab_icon_new, - null), - - EXPLORE(3, R.string.main_tab_name_explore, R.drawable.tab_icon_explore, - ExploreFragment.class), - - ME(4, R.string.main_tab_name_my, R.drawable.tab_icon_me, - MyInformationFragment.class); - - private int idx; - private int resName; - private int resIcon; - private Class clz; - - private MainTab(int idx, int resName, int resIcon, Class clz) { - this.idx = idx; - this.resName = resName; - this.resIcon = resIcon; - this.clz = clz; - } - - public int getIdx() { - return idx; - } - - public void setIdx(int idx) { - this.idx = idx; - } - - public int getResName() { - return resName; - } - - public void setResName(int resName) { - this.resName = resName; - } - - public int getResIcon() { - return resIcon; - } - - public void setResIcon(int resIcon) { - this.resIcon = resIcon; - } - - public Class getClz() { - return clz; - } - - public void setClz(Class clz) { - this.clz = clz; - } -} diff --git a/app/src/main/java/net/oschina/app/ui/MyQrodeDialog.java b/app/src/main/java/net/oschina/app/ui/MyQRCodeDialog.java similarity index 83% rename from app/src/main/java/net/oschina/app/ui/MyQrodeDialog.java rename to app/src/main/java/net/oschina/app/ui/MyQRCodeDialog.java index 69d253b031163a5c62e8fafdecfadfe43c2c3116..032a356cabfccd3b98579d4f0fa1cba99609ccfd 100644 --- a/app/src/main/java/net/oschina/app/ui/MyQrodeDialog.java +++ b/app/src/main/java/net/oschina/app/ui/MyQRCodeDialog.java @@ -19,30 +19,30 @@ import com.google.zxing.WriterException; import net.oschina.app.AppContext; import net.oschina.app.R; +import net.oschina.app.improve.account.AccountHelper; import net.oschina.app.util.QrCodeUtils; import org.kymjs.kjframe.utils.FileUtils; -public class MyQrodeDialog extends Dialog { +public class MyQRCodeDialog extends Dialog { private ImageView mIvCode; private Bitmap bitmap; - private MyQrodeDialog(Context context, boolean flag, - OnCancelListener listener) { + private MyQRCodeDialog(Context context, boolean flag, + OnCancelListener listener) { super(context, flag, listener); } @SuppressLint("InflateParams") - private MyQrodeDialog(Context context, int defStyle) { + private MyQRCodeDialog(Context context, int defStyle) { super(context, defStyle); View contentView = getLayoutInflater().inflate( R.layout.dialog_my_qr_code, null); mIvCode = (ImageView) contentView.findViewById(R.id.iv_qr_code); try { bitmap = QrCodeUtils.Create2DCode(String.format( - "http://my.oschina.net/u/%s", AppContext.getInstance() - .getLoginUid())); + "http://my.oschina.net/u/%s", AccountHelper.getUserId())); mIvCode.setImageBitmap(bitmap); } catch (WriterException e) { e.printStackTrace(); @@ -65,15 +65,15 @@ public class MyQrodeDialog extends Dialog { contentView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { - MyQrodeDialog.this.dismiss(); + MyQRCodeDialog.this.dismiss(); return false; } }); super.setContentView(contentView); } - public MyQrodeDialog(Context context) { - this(context, R.style.quick_option_dialog); + public MyQRCodeDialog(Context context) { + this(context, R.style.App_Theme_Tweet_Main); } diff --git a/app/src/main/java/net/oschina/app/ui/NavigationDrawerFragment.java b/app/src/main/java/net/oschina/app/ui/NavigationDrawerFragment.java deleted file mode 100644 index ad0c77d8daa6ce2a0e9300841b1cfedcb0e0bc8d..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/ui/NavigationDrawerFragment.java +++ /dev/null @@ -1,312 +0,0 @@ -package net.oschina.app.ui; - -import android.app.Activity; -import android.content.res.Configuration; -import android.os.Bundle; -import android.support.v4.view.GravityCompat; -import android.support.v4.widget.DrawerLayout; -import android.support.v7.app.ActionBar; -import android.support.v7.app.ActionBarActivity; -import android.support.v7.app.ActionBarDrawerToggle; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.TextView; - -import net.oschina.app.AppContext; -import net.oschina.app.R; -import net.oschina.app.base.BaseFragment; -import net.oschina.app.bean.SimpleBackPage; -import net.oschina.app.util.TDevice; -import net.oschina.app.util.UIHelper; - -import butterknife.ButterKnife; -import butterknife.InjectView; - -/** - * 侧滑菜单界面 - * - * @author FireAnt(http://my.oschina.net/LittleDY) - * @created 2014年9月25日 下午6:00:05 - */ -public class NavigationDrawerFragment extends BaseFragment implements - OnClickListener { - - /** - * Remember the position of the selected item. - */ - private static final String STATE_SELECTED_POSITION = "selected_navigation_drawer_position"; - - /** - * A pointer to the current callbacks instance (the Activity). - */ - private NavigationDrawerCallbacks mCallbacks; - - /** - * Helper component that ties the action bar to the navigation drawer. - */ - private ActionBarDrawerToggle mDrawerToggle; - - private DrawerLayout mDrawerLayout; - private View mDrawerListView; - private View mFragmentContainerView; - - private int mCurrentSelectedPosition = 0; - private boolean mFromSavedInstanceState; - - @InjectView(R.id.menu_item_quests) - View mMenu_item_quests; - - @InjectView(R.id.menu_item_opensoft) - View mMenu_item_opensoft; - - @InjectView(R.id.menu_item_blog) - View mMenu_item_blog; - - @InjectView(R.id.menu_item_gitapp) - View mMenu_item_gitapp; - - @InjectView(R.id.menu_item_setting) - View mMenu_item_setting; - - @InjectView(R.id.menu_item_theme) - View mMenu_item_theme; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - if (savedInstanceState != null) { - mCurrentSelectedPosition = savedInstanceState - .getInt(STATE_SELECTED_POSITION); - mFromSavedInstanceState = true; - } - - selectItem(mCurrentSelectedPosition); - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - setHasOptionsMenu(true); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - mDrawerListView = inflater.inflate(R.layout.fragment_navigation_drawer, - container, false); - mDrawerListView.setOnClickListener(this); - ButterKnife.inject(this, mDrawerListView); - initView(mDrawerListView); - initData(); - return mDrawerListView; - } - - @Override - public void onClick(View v) { - int id = v.getId(); - switch (id) { - case R.id.menu_item_quests: - UIHelper.showSimpleBack(getActivity(), SimpleBackPage.QUEST); - break; - case R.id.menu_item_opensoft: - UIHelper.showSimpleBack(getActivity(), - SimpleBackPage.OPENSOURCE_SOFTWARE); - break; - case R.id.menu_item_blog: - UIHelper.showSimpleBack(getActivity(), SimpleBackPage.BLOG); - break; - case R.id.menu_item_gitapp: - - boolean res = TDevice.openAppActivity(getActivity(), - "net.oschina.gitapp", "net.oschina.gitapp.WelcomePage"); - - if (!res) { - if (!TDevice.isHaveMarket(getActivity())) { - UIHelper.openSysBrowser(getActivity(), - "http://git.oschina.net/appclient"); - } else { - TDevice.gotoMarket(getActivity(), "net.oschina.gitapp"); - } - } - break; - case R.id.menu_item_setting: - UIHelper.showSetting(getActivity()); - break; - case R.id.menu_item_theme: - switchTheme(); - break; - default: - break; - - } - mDrawerLayout.postDelayed(new Runnable() { - - @Override - public void run() { - mDrawerLayout.closeDrawers(); - } - }, 800); - } - - private void switchTheme() { - if (AppContext.getNightModeSwitch()) { - AppContext.setNightModeSwitch(false); - } else { - AppContext.setNightModeSwitch(true); - } - - if (AppContext.getNightModeSwitch()) { - getActivity().setTheme(R.style.AppBaseTheme_Night); - } else { - getActivity().setTheme(R.style.AppBaseTheme_Light); - } - - getActivity().recreate(); - } - - @Override - public void initView(View view) { - - TextView night = (TextView) view.findViewById(R.id.tv_night); - if (AppContext.getNightModeSwitch()) { - night.setText("日间"); - } else { - night.setText("夜间"); - } - - mMenu_item_opensoft.setOnClickListener(this); - mMenu_item_blog.setOnClickListener(this); - mMenu_item_quests.setOnClickListener(this); - - mMenu_item_setting.setOnClickListener(this); - mMenu_item_theme.setOnClickListener(this); - - mMenu_item_gitapp.setOnClickListener(this); - } - - @Override - public void initData() { - } - - public boolean isDrawerOpen() { - return mDrawerLayout != null - && mDrawerLayout.isDrawerOpen(mFragmentContainerView); - } - - /** - * Users of this fragment must call this method to set up the navigation - * drawer interactions. - * - * @param fragmentId The android:id of this fragment in its activity's layout. - * @param drawerLayout The DrawerLayout containing this fragment's UI. - */ - public void setUp(int fragmentId, DrawerLayout drawerLayout) { - mFragmentContainerView = getActivity().findViewById(fragmentId); - mDrawerLayout = drawerLayout; - - // set a custom shadow that overlays the main content when the drawer - // opens - mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, - GravityCompat.START); - // set up the drawer's list view with items and click listener - - ActionBar actionBar = getActionBar(); - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setHomeButtonEnabled(true); - - mDrawerToggle = new ActionBarDrawerToggle(getActivity(), mDrawerLayout, - null, R.string.navigation_drawer_open, - R.string.navigation_drawer_close) { - - public void onDrawerClosed(View view) { - super.onDrawerClosed(view); - getActivity().invalidateOptionsMenu(); - } - - public void onDrawerOpened(View drawerView) { - super.onDrawerOpened(drawerView); - getActivity().invalidateOptionsMenu(); - } - }; - - mDrawerLayout.post(new Runnable() { - @Override - public void run() { - mDrawerToggle.syncState(); - } - }); - - mDrawerLayout.setDrawerListener(mDrawerToggle); - } - - public void openDrawerMenu() { - mDrawerLayout.openDrawer(mFragmentContainerView); - } - - private void selectItem(int position) { - mCurrentSelectedPosition = position; - if (mDrawerLayout != null) { - mDrawerLayout.closeDrawer(mFragmentContainerView); - } - if (mCallbacks != null) { - mCallbacks.onNavigationDrawerItemSelected(position); - } - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - try { - mCallbacks = (NavigationDrawerCallbacks) activity; - } catch (ClassCastException e) { - throw new ClassCastException( - "Activity must implement NavigationDrawerCallbacks."); - } - } - - @Override - public void onDetach() { - super.onDetach(); - mCallbacks = null; - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putInt(STATE_SELECTED_POSITION, mCurrentSelectedPosition); - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - mDrawerToggle.onConfigurationChanged(newConfig); - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - super.onCreateOptionsMenu(menu, inflater); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (mDrawerToggle.onOptionsItemSelected(item)) { - return true; - } - - return super.onOptionsItemSelected(item); - } - - private ActionBar getActionBar() { - return ((ActionBarActivity) getActivity()).getSupportActionBar(); - } - - public interface NavigationDrawerCallbacks { - void onNavigationDrawerItemSelected(int position); - } -} diff --git a/app/src/main/java/net/oschina/app/ui/OSCPhotosActivity.java b/app/src/main/java/net/oschina/app/ui/OSCPhotosActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..b19a461310805a35c9a4623d7a39a938b598b599 --- /dev/null +++ b/app/src/main/java/net/oschina/app/ui/OSCPhotosActivity.java @@ -0,0 +1,175 @@ +package net.oschina.app.ui; + +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.os.Bundle; +import android.view.View; +import android.view.WindowManager; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.animation.GlideAnimation; +import com.bumptech.glide.request.target.SimpleTarget; + +import net.oschina.app.AppConfig; +import net.oschina.app.AppContext; +import net.oschina.app.R; +import net.oschina.app.base.BaseActivity; +import net.oschina.app.ui.dialog.ImageMenuDialog; +import net.oschina.app.util.ImageUtils; +import net.oschina.app.util.TDevice; +import net.oschina.app.widget.TouchImageView; + +import java.io.IOException; + +/** + * 图片预览界面 + */ +public class OSCPhotosActivity extends BaseActivity { + + public static final String BUNDLE_KEY_IMAGES = "bundle_key_images"; + private TouchImageView mTouchImageView; + private ProgressBar mProgressBar; + private ImageView mOption; + private String mImageUrl; + + public static void showImagePreview(Context context, + String imageUrl) { + Intent intent = new Intent(context, OSCPhotosActivity.class); + intent.putExtra(BUNDLE_KEY_IMAGES, imageUrl); + context.startActivity(intent); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + } + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_photo_browse); + mImageUrl = getIntent().getStringExtra(BUNDLE_KEY_IMAGES); + + mTouchImageView = (TouchImageView) findViewById(R.id.photoview); + + mTouchImageView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + + mProgressBar = (ProgressBar) findViewById(R.id.pb_loading); + + mOption = (ImageView) findViewById(R.id.iv_more); + mOption.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + showOptionMenu(); + } + }); + + loadImage(mTouchImageView, mImageUrl); + + if (getSupportActionBar() != null) { + getSupportActionBar().hide(); + } + } + + private void showOptionMenu() { + final ImageMenuDialog dialog = new ImageMenuDialog(this); + dialog.show(); + dialog.setCancelable(true); + dialog.setOnMenuClickListener(new ImageMenuDialog.OnMenuClickListener() { + @Override + public void onClick(TextView menuItem) { + if (menuItem.getId() == R.id.menu1) { + saveImg(); + } else if (menuItem.getId() == R.id.menu2) { + sendTweet(); + } else if (menuItem.getId() == R.id.menu3) { + copyUrl(); + } + dialog.dismiss(); + } + }); + } + + /** + * 复制链接 + */ + private void copyUrl() { + TDevice.copyTextToBoard(mImageUrl); + AppContext.showToastShort("已复制到剪贴板"); + } + + /** + * 发送到动弹 + */ + private void sendTweet() { + finish(); + } + + /** + * 保存图片 + */ + private void saveImg() { + final String filePath = AppConfig.DEFAULT_SAVE_IMAGE_PATH + + getFileName(mImageUrl); + + Drawable drawable = mTouchImageView.getDrawable(); + if (drawable != null && drawable instanceof BitmapDrawable) { + Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap(); + try { + ImageUtils.saveImageToSD(this, filePath, bitmap, 100); + AppContext.showToastShort(getString(R.string.tip_save_image_suc)); + } catch (IOException e) { + e.printStackTrace(); + } + } + //Core.getKJBitmap().saveImage(this, mImageUrl, filePath); + } + + private String getFileName(String imgUrl) { + int index = imgUrl.lastIndexOf('/') + 1; + if (index == -1) { + return System.currentTimeMillis() + ".jpeg"; + } + return imgUrl.substring(index); + } + + /** + * Load the item's thumbnail image into our {@link ImageView}. + */ + private void loadImage(final ImageView mHeaderImageView, final String imageUrl) { + Glide.with(this).load(imageUrl).asBitmap().into(new SimpleTarget() { + @Override + public void onResourceReady(Bitmap resource, GlideAnimation glideAnimation) { + mHeaderImageView.setImageBitmap(resource); + mProgressBar.setVisibility(View.GONE); + mHeaderImageView.setVisibility(View.VISIBLE); + mOption.setVisibility(View.VISIBLE); + } + }); + } + + @Override + public void onClick(View v) { + + } + + @Override + public void initView() { + + } + + @Override + public void initData() { + + } +} diff --git a/app/src/main/java/net/oschina/app/ui/QuickOptionDialog.java b/app/src/main/java/net/oschina/app/ui/QuickOptionDialog.java deleted file mode 100644 index d38489acbc282f1898cce94f991576d0dc8b0eb7..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/ui/QuickOptionDialog.java +++ /dev/null @@ -1,161 +0,0 @@ -package net.oschina.app.ui; - -import android.annotation.SuppressLint; -import android.app.Dialog; -import android.content.Context; -import android.os.Bundle; -import android.view.Display; -import android.view.Gravity; -import android.view.MotionEvent; -import android.view.View; -import android.view.Window; -import android.view.WindowManager; -import android.view.animation.Animation; -import android.view.animation.AnimationUtils; -import android.view.animation.LinearInterpolator; -import android.widget.ImageView; - -import net.oschina.app.R; -import net.oschina.app.bean.SimpleBackPage; -import net.oschina.app.fragment.TweetPubFragment; -import net.oschina.app.team.fragment.NoteEditFragment; -import net.oschina.app.util.UIHelper; - -public class QuickOptionDialog extends Dialog implements - android.view.View.OnClickListener { - - private ImageView mClose; - - public interface OnQuickOptionformClick { - void onQuickOptionClick(int id); - } - - private OnQuickOptionformClick mListener; - - private QuickOptionDialog(Context context, boolean flag, - OnCancelListener listener) { - super(context, flag, listener); - } - - @SuppressLint("InflateParams") - private QuickOptionDialog(Context context, int defStyle) { - super(context, defStyle); - View contentView = getLayoutInflater().inflate( - R.layout.dialog_quick_option, null); - contentView.findViewById(R.id.ly_quick_option_text).setOnClickListener( - this); - contentView.findViewById(R.id.ly_quick_option_album) - .setOnClickListener(this); - contentView.findViewById(R.id.ly_quick_option_photo) - .setOnClickListener(this); - contentView.findViewById(R.id.ly_quick_option_voice) - .setOnClickListener(this); - contentView.findViewById(R.id.ly_quick_option_scan).setOnClickListener( - this); - contentView.findViewById(R.id.ly_quick_option_note).setOnClickListener( - this); - mClose = (ImageView) contentView.findViewById(R.id.iv_close); - - Animation operatingAnim = AnimationUtils.loadAnimation(getContext(), - R.anim.quick_option_close); - LinearInterpolator lin = new LinearInterpolator(); - operatingAnim.setInterpolator(lin); - - mClose.startAnimation(operatingAnim); - - mClose.setOnClickListener(this); - requestWindowFeature(Window.FEATURE_NO_TITLE); - contentView.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - QuickOptionDialog.this.dismiss(); - return true; - } - }); - super.setContentView(contentView); - - } - - public QuickOptionDialog(Context context) { - this(context, R.style.quick_option_dialog); - } - - @SuppressWarnings("deprecation") - @Override - protected void onCreate(Bundle bundle) { - super.onCreate(bundle); - getWindow().setGravity(Gravity.BOTTOM); - - WindowManager m = getWindow().getWindowManager(); - Display d = m.getDefaultDisplay(); - WindowManager.LayoutParams p = getWindow().getAttributes(); - p.width = d.getWidth(); - getWindow().setAttributes(p); - } - - public void setOnQuickOptionformClickListener(OnQuickOptionformClick lis) { - mListener = lis; - } - - @Override - public void onClick(View v) { - final int id = v.getId(); - switch (id) { - case R.id.iv_close: - dismiss(); - break; - case R.id.ly_quick_option_text: - onClickTweetPub(R.id.ly_quick_option_text); - break; - case R.id.ly_quick_option_album: - onClickTweetPub(R.id.ly_quick_option_album); - break; - case R.id.ly_quick_option_photo: - onClickTweetPub(R.id.ly_quick_option_photo); - break; - case R.id.ly_quick_option_voice: - UIHelper.showSimpleBack(getContext(), SimpleBackPage.RECORD); - break; - case R.id.ly_quick_option_scan: - UIHelper.showScanActivity(getContext()); - break; - case R.id.ly_quick_option_note: - // UIHelper.showSimpleBack(getContext(), SimpleBackPage.FIND_USER); - onClickNote(); - //UIHelper.showSimpleBack(getContext(), SimpleBackPage.FIND_USER); - // onClickNote(); - break; - default: - break; - } - if (mListener != null) { - mListener.onQuickOptionClick(id); - } - dismiss(); - } - - private void onClickTweetPub(int id) { - Bundle bundle = new Bundle(); - int type = -1; - switch (id) { - case R.id.ly_quick_option_album: - type = TweetPubFragment.ACTION_TYPE_ALBUM; - break; - case R.id.ly_quick_option_photo: - type = TweetPubFragment.ACTION_TYPE_PHOTO; - break; - default: - break; - } - bundle.putInt(TweetPubFragment.ACTION_TYPE, type); - UIHelper.showTweetActivity(getContext(), SimpleBackPage.TWEET_PUB, - bundle); - } - - private void onClickNote() { - Bundle bundle = new Bundle(); - bundle.putInt(NoteEditFragment.NOTE_FROMWHERE_KEY, - NoteEditFragment.QUICK_DIALOG); - UIHelper.showSimpleBack(getContext(), SimpleBackPage.NOTE_EDIT, bundle); - } -} \ No newline at end of file diff --git a/app/src/main/java/net/oschina/app/ui/ReportDialog.java b/app/src/main/java/net/oschina/app/ui/ReportDialog.java index 275ec01d8e04d0cd72f53ce5e1dbd463b1e01597..a9a4b27bf635bdb2bdb07e3c64b08570113d3655 100644 --- a/app/src/main/java/net/oschina/app/ui/ReportDialog.java +++ b/app/src/main/java/net/oschina/app/ui/ReportDialog.java @@ -10,8 +10,8 @@ import android.widget.TextView; import net.oschina.app.R; import net.oschina.app.bean.Report; +import net.oschina.app.improve.utils.DialogHelper; import net.oschina.app.ui.dialog.CommonDialog; -import net.oschina.app.util.DialogHelp; import net.oschina.app.util.TDevice; public class ReportDialog extends CommonDialog implements @@ -23,15 +23,15 @@ public class ReportDialog extends CommonDialog implements private String[] reasons; private int reasonIndex; private String mUrl; - private int mObjId; + private long mObjId; private byte mObjType; - public ReportDialog(Context context, String url, int objId, byte objType) { + public ReportDialog(Context context, String url, long objId, byte objType) { this(context, R.style.dialog_common, url, objId, objType); } private ReportDialog(Context context, int defStyle, String url, - int objId, byte objType) { + long objId, byte objType) { super(context, defStyle); this.mUrl = url; this.mObjId = objId; @@ -75,7 +75,7 @@ public class ReportDialog extends CommonDialog implements AlertDialog reson = null; private void selectReason() { - reson = DialogHelp.getSingleChoiceDialog(getContext(), "举报原因", reasons, reasonIndex, new OnClickListener() { + reson = DialogHelper.getSingleChoiceDialog(getContext(), "举报原因", reasons, reasonIndex, new OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { mTvReason.setText(reasons[i]); diff --git a/app/src/main/java/net/oschina/app/ui/SelectFriendsActivity.java b/app/src/main/java/net/oschina/app/ui/SelectFriendsActivity.java index 45f72f91d6bf06e46754d5b1ec3782308490dca1..e647ffdf43f5180337a1f1e97233a118b3284345 100644 --- a/app/src/main/java/net/oschina/app/ui/SelectFriendsActivity.java +++ b/app/src/main/java/net/oschina/app/ui/SelectFriendsActivity.java @@ -1,11 +1,13 @@ package net.oschina.app.ui; +import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.os.Build; +import android.support.v4.app.Fragment; import android.support.v4.view.MotionEventCompat; import android.support.v4.view.ViewCompat; import android.support.v7.app.ActionBar; @@ -39,6 +41,7 @@ import net.oschina.app.base.BaseActivity; import net.oschina.app.bean.Friend; import net.oschina.app.bean.FriendsList; import net.oschina.app.cache.CacheManager; +import net.oschina.app.improve.account.AccountHelper; import net.oschina.app.ui.empty.EmptyLayout; import net.oschina.app.util.StringUtils; import net.oschina.app.util.TDevice; @@ -51,7 +54,6 @@ import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat; import net.sourceforge.pinyin4j.format.HanyuPinyinToneType; import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType; - import java.io.ByteArrayInputStream; import java.io.Serializable; import java.lang.ref.WeakReference; @@ -60,7 +62,7 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; -import butterknife.InjectView; +import butterknife.Bind; import cz.msebera.android.httpclient.Header; /** @@ -69,62 +71,65 @@ import cz.msebera.android.httpclient.Header; *

    LeonLee Blog

    * * @author 李文龙(LeonLee) - * - * 选择好友界面 - * + *

    + * 选择好友界面 */ public class SelectFriendsActivity extends BaseActivity { private static final String TAG = "SelectFriendsActivity"; - /** 最大可选择好友的数量*/ + /** + * 最大可选择好友的数量 + */ private static final int MAX_SELECTED_SIZE = 10; - /** 数据缓存有效时间*/ + /** + * 数据缓存有效时间 + */ private static final int CACHE_TIME = 2 * 60; //2分钟 private static final String CACHE_KEY_PREFIX = "friend_list_all"; - @InjectView(R.id.lv_list) + @Bind(R.id.lv_list) ListView mListView; - @InjectView(R.id.error_layout) + @Bind(R.id.error_layout) EmptyLayout mEmptyLayout; - @InjectView(R.id.search_list) + @Bind(R.id.search_list) ListView mSearchListView; - @InjectView(R.id.et_search) + @Bind(R.id.et_search) EditText mSearchEditText; - @InjectView(R.id.float_text) + @Bind(R.id.float_text) TextView mFloatTextView; - @InjectView(R.id.indexview) + @Bind(R.id.indexview) IndexView mIndexView; - @InjectView(R.id.top_layout) + @Bind(R.id.top_layout) View topLayout; - @InjectView(R.id.hs_container) + @Bind(R.id.hs_container) HorizontalScrollView mHorizontalScrollView; - @InjectView(R.id.select_container) + @Bind(R.id.select_container) ViewGroup mSelectContainer; - @InjectView(R.id.search_layout) + @Bind(R.id.search_layout) View mSearchLayout; - @InjectView(R.id.search_result_text) + @Bind(R.id.search_result_text) View mSearchResultText; - @InjectView(R.id.iv_search) + @Bind(R.id.iv_search) View mSearchIcon; - @InjectView(R.id.divider1) + @Bind(R.id.divider1) View mDividerView1; - @InjectView(R.id.divider2) + @Bind(R.id.divider2) View mDividerView2; private TextView mTopRightButton; @@ -149,19 +154,35 @@ public class SelectFriendsActivity extends BaseActivity { //选中edittext的线条颜色 private int colorPrimary; + public static void show(Fragment fragment) { + Intent intent = new Intent(fragment.getActivity(), SelectFriendsActivity.class); + fragment.startActivityForResult(intent, 1); + } + + public static void show(Activity activity) { + Intent intent = new Intent(activity, SelectFriendsActivity.class); + activity.startActivityForResult(intent, 1); + } + @Override - public void onClick(View v) {} + public void onClick(View v) { + } - /** 创建一个空白的ListView头部*/ + /** + * 创建一个空白的ListView头部 + */ private View createListHeaderView() { View view = new View(this); - int headerHeight = getResources().getDimensionPixelOffset(R.dimen.select_friend_header_height); - AbsListView.LayoutParams lp = new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, headerHeight); + int headerHeight = getResources().getDimensionPixelOffset(R.dimen + .select_friend_header_height); + AbsListView.LayoutParams lp = new AbsListView.LayoutParams(ViewGroup.LayoutParams + .MATCH_PARENT, headerHeight); view.setLayoutParams(lp); return view; } @Override + @SuppressWarnings("ResourceType") public void initView() { TypedArray a = obtainStyledAttributes(new int[]{R.attr.lineColor, R.attr.colorPrimary}); lineColor = a.getColor(0, 0xFFDADADA); @@ -284,7 +305,7 @@ public class SelectFriendsActivity extends BaseActivity { //顶部设置透明度 View selectLayout = findViewById(R.id.select_layout); Drawable bg = selectLayout.getBackground(); - if(bg != null) { + if (bg != null) { bg.setAlpha(238); } @@ -298,9 +319,9 @@ public class SelectFriendsActivity extends BaseActivity { //添加右上角的按钮 ActionBar actionBar = getSupportActionBar(); - if(actionBar != null) { + if (actionBar != null) { actionBar.setDisplayShowCustomEnabled(true); - View view = getLayoutInflater().inflate(R.layout.actionbar_green_button_layout, null); + View view = View.inflate(this, R.layout.actionbar_green_button_layout, null); mTopRightButton = (TextView) view.findViewById(R.id.button); mTopRightButton.setText(R.string.ok); mTopRightButton.setEnabled(false); @@ -311,8 +332,8 @@ public class SelectFriendsActivity extends BaseActivity { } }); - ActionBar.LayoutParams lp = new ActionBar.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, - ViewGroup.LayoutParams.WRAP_CONTENT); + ActionBar.LayoutParams lp = new ActionBar.LayoutParams(ViewGroup.LayoutParams + .WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); lp.gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL; actionBar.setCustomView(view, lp); } @@ -330,7 +351,8 @@ public class SelectFriendsActivity extends BaseActivity { } @Override - public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { + public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int + totalItemCount) { //是否滚动到顶部 if (ViewCompat.canScrollVertically(view, -1)) { mDividerView2.setVisibility(View.VISIBLE); @@ -361,22 +383,25 @@ public class SelectFriendsActivity extends BaseActivity { return true; } - /** 点击列表*/ + /** + * 点击列表 + */ private void itemClick(FriendItem item) { boolean isSelected = !item.isSelected; int userId = item.friend.getUserid(); boolean contains = mCheckedFriendIds.contains(userId); if (isSelected) { if (mCheckedFriendIds.size() < MAX_SELECTED_SIZE) { - if(!contains) { + if (!contains) { mCheckedFriendIds.add(userId); - item.isSelected = isSelected; + item.isSelected = true; mAdapter.notifyDataSetChanged(); addHeaderSelectView(item.friend); } } else { - AppContext.showToast(getString(R.string.select_friends_max_tips, MAX_SELECTED_SIZE)); + AppContext.showToast(getString(R.string.select_friends_max_tips, + MAX_SELECTED_SIZE)); } } else { if (contains) { @@ -386,7 +411,7 @@ public class SelectFriendsActivity extends BaseActivity { iterator.remove(); } } - item.isSelected = isSelected; + item.isSelected = false; mAdapter.notifyDataSetChanged(); removeHeaderSelectView(userId); @@ -395,33 +420,38 @@ public class SelectFriendsActivity extends BaseActivity { updateTopButton(); } - /** 更新“确定”按钮*/ + /** + * 更新“确定”按钮 + */ private void updateTopButton() { String ok = getString(R.string.ok); - if(mCheckedFriendIds.isEmpty()) { + if (mCheckedFriendIds.isEmpty()) { mTopRightButton.setEnabled(false); mTopRightButton.setText(ok); } else { mTopRightButton.setEnabled(true); - mTopRightButton.setText(ok + "(" + mCheckedFriendIds.size() + "/" + MAX_SELECTED_SIZE + ")"); + mTopRightButton.setText(String.format("%s(%d/%d)", ok, mCheckedFriendIds.size(), + MAX_SELECTED_SIZE)); } } - /** 点击确定*/ + /** + * 点击确定 + */ private void clickOk() { - if(mCheckedFriendIds.isEmpty()) { + if (mCheckedFriendIds.isEmpty()) { setResult(RESULT_CANCELED); } else { Intent result = new Intent(); int userIds[] = new int[mCheckedFriendIds.size()]; String names[] = new String[mCheckedFriendIds.size()]; - for(int i = 0; i < mCheckedFriendIds.size(); i ++) { + for (int i = 0; i < mCheckedFriendIds.size(); i++) { int id = mCheckedFriendIds.get(i); userIds[i] = id; - for(FriendItem item : mAllFriendItems) { - if(item.friend.getUserid() == id) { + for (FriendItem item : mAllFriendItems) { + if (item.friend.getUserid() == id) { names[i] = item.friend.getName(); break; } @@ -434,63 +464,67 @@ public class SelectFriendsActivity extends BaseActivity { finish(); } - /** 清空搜索结果*/ + /** + * 清空搜索结果 + */ private void resetSearchResult() { mSearchResultList.clear(); } - /** 根据关键字去搜索*/ + /** + * 根据关键字去搜索 + */ private void searchKey(String key) { resetSearchResult(); - if(!TextUtils.isEmpty(key)) { + if (!TextUtils.isEmpty(key)) { key = key.toLowerCase(); int len = key.length(); int keyLength; int start; for (FriendItem item : mAllFriendItems) { String name = item.name; - if(TextUtils.isEmpty(name)) { + if (TextUtils.isEmpty(name)) { continue; } keyLength = len; //先按名字查找 start = name.indexOf(key); - if(start == -1) { + if (start == -1) { //判断是否是纯英文 - if(!key.matches("[a-zA-Z]+")) { + if (!key.matches("[a-zA-Z]+")) { continue; } boolean match = false; //判断是不是拼音 - if(!TextUtils.isEmpty(item.pinYin)) { - if(item.pinYin.startsWith(key)) { + if (!TextUtils.isEmpty(item.pinYin)) { + if (item.pinYin.startsWith(key)) { match = true; start = 0; int total = 0; - for(int i = 0; i < item.pinYinArray.length; i ++) { + for (int i = 0; i < item.pinYinArray.length; i++) { String py = item.pinYinArray[i]; total += py.length(); - if(len <= total) { + if (len <= total) { keyLength = i + 1; break; } } - } else if(key.startsWith(item.pinYin)) { + } else if (key.startsWith(item.pinYin)) { match = true; start = -1; keyLength = 0; } } - if(!match) { - if(!TextUtils.isEmpty(item.firstPinYin)) { + if (!match) { + if (!TextUtils.isEmpty(item.firstPinYin)) { //判断是不是首字母拼间 if (item.firstPinYin.startsWith(key)) { match = true; start = 0; keyLength = len; - } else if(key.startsWith(item.firstPinYin)) { + } else if (key.startsWith(item.firstPinYin)) { match = true; start = -1; keyLength = 0; @@ -498,7 +532,7 @@ public class SelectFriendsActivity extends BaseActivity { } } - if(!match) { + if (!match) { continue; } } @@ -506,7 +540,7 @@ public class SelectFriendsActivity extends BaseActivity { mSearchResultList.add(new SearchItem(item, start, keyLength, colorPrimary)); } } - if(mSearchResultList.isEmpty()) { + if (mSearchResultList.isEmpty()) { mSearchResultText.setVisibility(View.VISIBLE); } else { mSearchResultText.setVisibility(View.GONE); @@ -514,9 +548,11 @@ public class SelectFriendsActivity extends BaseActivity { mSearchAdapter.notifyDataSetChanged(); } - /** 设置输入模式*/ + /** + * 设置输入模式 + */ private void setEditMode(boolean edit) { - if(!edit) { + if (!edit) { //隐藏输入法 TDevice.hideSoftKeyboard(mSearchEditText); resetLastSelectView(); @@ -529,7 +565,9 @@ public class SelectFriendsActivity extends BaseActivity { isEditMode = edit; } - /** 添加顶部选中的用户头像*/ + /** + * 添加顶部选中的用户头像 + */ private void addHeaderSelectView(Friend friend) { mHorizontalScrollView.setVisibility(View.VISIBLE); mSearchIcon.setVisibility(View.GONE); @@ -538,7 +576,7 @@ public class SelectFriendsActivity extends BaseActivity { final AvatarView image = new AvatarView(this); image.setDisplayCircle(false); - image.setImageResource(R.drawable.widget_dface); + image.setImageResource(R.mipmap.widget_dface); image.setAvatarUrl(friend.getPortrait()); image.setTag(userId); @@ -556,7 +594,7 @@ public class SelectFriendsActivity extends BaseActivity { //修正HorizontalScrollView的大小 ViewGroup.LayoutParams layoutParams = mHorizontalScrollView.getLayoutParams(); - if(size + 10 + mHorizontalScrollView.getWidth() > topLayout.getWidth() - minSize + if (size + 10 + mHorizontalScrollView.getWidth() > topLayout.getWidth() - minSize && layoutParams.width == ViewGroup.LayoutParams.WRAP_CONTENT) { layoutParams.width = mHorizontalScrollView.getWidth(); mHorizontalScrollView.setLayoutParams(layoutParams); @@ -579,43 +617,49 @@ public class SelectFriendsActivity extends BaseActivity { }); } - /** 移除顶部选中的用户头像*/ + /** + * 移除顶部选中的用户头像 + */ private void removeHeaderSelectView(int userId) { View view = mSelectContainer.findViewWithTag(userId); - if(view != null) { + if (view != null) { //修正HorizontalScrollView的大小 ViewGroup.LayoutParams layoutParams = mHorizontalScrollView.getLayoutParams(); - if(layoutParams.width != ViewGroup.LayoutParams.WRAP_CONTENT) { + if (layoutParams.width != ViewGroup.LayoutParams.WRAP_CONTENT) { int minSize = (int) mSearchEditText.getPaint().measureText("搜 索"); - if(mSelectContainer.getWidth() - view.getWidth() <= topLayout.getWidth() - minSize ) + if (mSelectContainer.getWidth() - view.getWidth() <= topLayout.getWidth() - minSize) layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT; mHorizontalScrollView.setLayoutParams(layoutParams); } mSelectContainer.removeView(view); } - if(mSelectContainer.getChildCount() == 0) { + if (mSelectContainer.getChildCount() == 0) { mSearchIcon.setVisibility(View.VISIBLE); mHorizontalScrollView.setVisibility(View.GONE); } } - /** 恢复最后的选中状态的界面的透明度*/ + /** + * 恢复最后的选中状态的界面的透明度 + */ private void resetLastSelectView() { - if(mSelectContainer.getChildCount() == 0) { + if (mSelectContainer.getChildCount() == 0) { return; } View view = mSelectContainer.getChildAt(mSelectContainer.getChildCount() - 1); int key = R.id.select_container; view.setTag(key, null); - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { view.setAlpha(1); } } - /** 处理删除按键的事件*/ + /** + * 处理删除按键的事件 + */ private void handleDeleteKeyEvent() { - if(mSelectContainer.getChildCount() == 0) { + if (mSelectContainer.getChildCount() == 0) { return; } View view = mSelectContainer.getChildAt(mSelectContainer.getChildCount() - 1); @@ -625,9 +669,9 @@ public class SelectFriendsActivity extends BaseActivity { Integer count = (Integer) view.getTag(key); //连续点两次删除键才删除选中的项 - if(count == null || count == 0) { + if (count == null || count == 0) { view.setTag(key, 1); - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { view.setAlpha(0.5f); } } else { @@ -635,7 +679,9 @@ public class SelectFriendsActivity extends BaseActivity { } } - /** 移除一个已选择的好友*/ + /** + * 移除一个已选择的好友 + */ private void removeCheckedFriend(int userId) { Iterator iterator = mCheckedFriendIds.iterator(); while (iterator.hasNext()) { @@ -643,8 +689,8 @@ public class SelectFriendsActivity extends BaseActivity { iterator.remove(); } } - for(FriendItem item : mAllFriendItems) { - if(item.friend.getUserid() == userId) { + for (FriendItem item : mAllFriendItems) { + if (item.friend.getUserid() == userId) { item.isSelected = false; break; } @@ -671,15 +717,16 @@ public class SelectFriendsActivity extends BaseActivity { private transient boolean isSelected; - public FriendItem(Friend friend, String name, String indexStr, String pinYinArray[], String pinYin, String firstPinYin) { + public FriendItem(Friend friend, String name, String indexStr, String pinYinArray[], + String pinYin, String firstPinYin) { this.friend = friend; this.name = name; this.indexStr = indexStr; this.pinYinArray = pinYinArray; this.pinYin = pinYin; this.firstPinYin = firstPinYin; - - if(indexStr != null && indexStr.length() >= 0) { + + if (indexStr != null && indexStr.length() >= 0) { this.firstLetter = indexStr.charAt(0); } } @@ -719,7 +766,8 @@ public class SelectFriendsActivity extends BaseActivity { //高亮显示的颜色值 private int hightLightColor; - public SearchItem(FriendItem friendItem, int startIndex, int keyLength, int hightLightColor) { + public SearchItem(FriendItem friendItem, int startIndex, int keyLength, int + hightLightColor) { this.friendItem = friendItem; this.startIndex = startIndex; this.keyLength = keyLength; @@ -749,18 +797,16 @@ public class SelectFriendsActivity extends BaseActivity { /*** * 获取列表数据 - * @return void - * @param refresh */ private void requestData(boolean refresh) { - int uid = AppContext.getInstance().getLoginUid(); + int uid = (int) AccountHelper.getUserId(); String key = getCacheKey(uid); - if(refresh) { + if (refresh) { // 读取新的数据 sendRequestData(uid, key); } else { boolean hasCache = CacheManager.isExistDataCache(this, key); - if(hasCache) { + if (hasCache) { readCacheData(key); } else { sendRequestData(uid, key); @@ -768,19 +814,21 @@ public class SelectFriendsActivity extends BaseActivity { } } - /** 请求数据*/ + /** + * 请求数据 + */ private void sendRequestData(int uid, String key) { - if(uid == 0) { + if (uid == 0) { mEmptyLayout.setNoDataContent(getString(R.string.select_friends_empty)); mEmptyLayout.setErrorType(EmptyLayout.NODATA); } else { - if(TDevice.hasInternet()) { - if(mAllFriendItems.isEmpty()) { + if (TDevice.hasInternet()) { + if (mAllFriendItems.isEmpty()) { mEmptyLayout.setErrorType(EmptyLayout.NETWORK_LOADING); } OSChinaApi.getAllFriendsList(uid, relation, new ResponseHandler(this, key)); } else { - if(mAllFriendItems.isEmpty()) { + if (mAllFriendItems.isEmpty()) { mEmptyLayout.setErrorType(EmptyLayout.NETWORK_ERROR); } } @@ -798,10 +846,12 @@ public class SelectFriendsActivity extends BaseActivity { mCacheTask.execute(); } - /** 回调成功的数据*/ + /** + * 回调成功的数据 + */ private void handleResult(String cacheKey, boolean fromCache, List list) { - if(list.isEmpty()) { - if(mAllFriendItems.isEmpty()) { + if (list.isEmpty()) { + if (mAllFriendItems.isEmpty()) { mEmptyLayout.setNoDataContent(getString(R.string.select_friends_empty)); mEmptyLayout.setErrorType(EmptyLayout.NODATA); } else { @@ -809,33 +859,37 @@ public class SelectFriendsActivity extends BaseActivity { } } else { mEmptyLayout.setErrorType(EmptyLayout.HIDE_LAYOUT); - if(mAllFriendItems.isEmpty() || (!isEditMode && mCheckedFriendIds.isEmpty())) { + if (mAllFriendItems.isEmpty() || (!isEditMode && mCheckedFriendIds.isEmpty())) { mAllFriendItems.clear(); mAllFriendItems.addAll(list); mAdapter.setFriendItems(mAllFriendItems); } } - if(fromCache) { - String lastRefreshTime = AppContext.getLastRefreshTime(cacheKey); - String currTime = StringUtils.getCurTimeStr(); + if (fromCache) { + String lastRefreshTime = "0";// AppContext.getLastRefreshTime(cacheKey); + String currTime = StringUtils.getCurrentTimeStr(); long diff = StringUtils.calDateDifferent(lastRefreshTime, currTime); - if(diff > CACHE_TIME) { //缓存超过有效时间,则重新请求数据 + if (diff > CACHE_TIME) { //缓存超过有效时间,则重新请求数据 requestData(true); } } } - /** 回调失败的结果*/ + /** + * 回调失败的结果 + */ private void handleFail() { //如果为空时,才显示没有数据的提示 - if(mAllFriendItems.isEmpty()) { + if (mAllFriendItems.isEmpty()) { mEmptyLayout.setNoDataContent(getString(R.string.select_friends_empty)); mEmptyLayout.setErrorType(EmptyLayout.NODATA); } } - /** 读取缓存任务*/ + /** + * 读取缓存任务 + */ private static class CacheTask extends AsyncTask> { private final WeakReference mActivity; private final String cacheKey; @@ -848,20 +902,21 @@ public class SelectFriendsActivity extends BaseActivity { @Override protected List doInBackground(Void... params) { SelectFriendsActivity activity = mActivity.get(); - if(activity == null) { + if (activity == null) { return null; } - return (List) CacheManager.readObject(activity.getApplicationContext(), cacheKey); + return (List) CacheManager.readObject(activity.getApplicationContext(), + cacheKey); } @Override protected void onPostExecute(List list) { SelectFriendsActivity activity = mActivity.get(); - if(activity == null || activity.isFinishing()) { + if (activity == null || activity.isFinishing()) { return; } //如果缓存为空,则读取网络的数据 - if(list == null || list.isEmpty()) { + if (list == null || list.isEmpty()) { activity.requestData(true); } else { activity.handleResult(cacheKey, true, list); @@ -869,7 +924,9 @@ public class SelectFriendsActivity extends BaseActivity { } } - /** 网络请求回调*/ + /** + * 网络请求回调 + */ private static class ResponseHandler extends AsyncHttpResponseHandler { private final WeakReference mActivity; @@ -883,7 +940,8 @@ public class SelectFriendsActivity extends BaseActivity { } @Override - public void onSuccess(final int statusCode, final Header[] headers, final byte[] responseBody) { + public void onSuccess(final int statusCode, final Header[] headers, final byte[] + responseBody) { //对数据进行异常解析 new AsyncTask>() { @@ -906,12 +964,12 @@ public class SelectFriendsActivity extends BaseActivity { String name; char[] input; - for(Friend friend : friendsList.getList()) { + for (Friend friend : friendsList.getList()) { indexStr.replace(0, indexStr.length(), ""); firstPinYin.replace(0, firstPinYin.length(), ""); pinYin.replace(0, pinYin.length(), ""); - if(TextUtils.isEmpty(friend.getName())) { + if (TextUtils.isEmpty(friend.getName())) { name = ""; } else { name = friend.getName().toLowerCase(); @@ -923,16 +981,18 @@ public class SelectFriendsActivity extends BaseActivity { //判断是否为中文 if (str.matches("[\u4E00-\u9FA5]+")) { try { - String[] temp = PinyinHelper.toHanyuPinyinStringArray(c, format); + String[] temp = PinyinHelper.toHanyuPinyinStringArray + (c, format); String pinyin = temp[0]; if (!TextUtils.isEmpty(pinyin)) { indexStr.append(pinyin); - if(lastCNChar) { + if (lastCNChar) { pinYin.append(pinyin).append(" "); firstPinYin.append(pinyin.charAt(0)); } } - } catch (Exception e){} + } catch (Exception e) { + } } else { lastCNChar = false; indexStr.append(str); @@ -942,7 +1002,8 @@ public class SelectFriendsActivity extends BaseActivity { String py = pinYin.toString(); String pyArray[] = py.split(" "); py = py.replace(" ", ""); - FriendItem item = new FriendItem(friend, name, indexStr.toString(), pyArray, + FriendItem item = new FriendItem(friend, name, indexStr.toString(), + pyArray, py, firstPinYin.toString()); newList.add(item); } @@ -952,7 +1013,7 @@ public class SelectFriendsActivity extends BaseActivity { //保存缓存结果 CacheManager.saveObject(applicationContext, newList, cacheKey); //记录保存时间 - AppContext.putToLastRefreshTime(cacheKey, StringUtils.getCurTimeStr()); + //AppContext.putToLastRefreshTime(cacheKey, StringUtils.getCurrentTimeStr()); return newList; } catch (Exception e) { e.printStackTrace(); @@ -963,10 +1024,10 @@ public class SelectFriendsActivity extends BaseActivity { @Override protected void onPostExecute(List friendItems) { SelectFriendsActivity activity = mActivity.get(); - if(activity == null || activity.isFinishing()) { + if (activity == null || activity.isFinishing()) { return; } - if(friendItems == null) { + if (friendItems == null) { onFailure(statusCode, headers, responseBody, null); } else { activity.handleResult(cacheKey, false, friendItems); @@ -976,9 +1037,10 @@ public class SelectFriendsActivity extends BaseActivity { } @Override - public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { + public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable + error) { SelectFriendsActivity activity = mActivity.get(); - if(activity == null) { + if (activity == null) { return; } activity.handleFail(); diff --git a/app/src/main/java/net/oschina/app/ui/ShakeActivity.java b/app/src/main/java/net/oschina/app/ui/ShakeActivity.java deleted file mode 100644 index 1ddd03665f0362c89d3af57bd41a2a79422f60f9..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/ui/ShakeActivity.java +++ /dev/null @@ -1,236 +0,0 @@ -package net.oschina.app.ui; - -import android.app.Service; -import android.content.Context; -import android.hardware.Sensor; -import android.hardware.SensorEvent; -import android.hardware.SensorEventListener; -import android.hardware.SensorManager; -import android.os.Vibrator; -import android.view.View; -import android.view.animation.Animation; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.ProgressBar; -import android.widget.TextView; - -import com.loopj.android.http.AsyncHttpResponseHandler; - -import net.oschina.app.AppContext; -import net.oschina.app.R; -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.base.BaseActivity; -import net.oschina.app.bean.ShakeObject; -import net.oschina.app.util.KJAnimations; -import net.oschina.app.util.StringUtils; -import net.oschina.app.util.TypefaceUtils; -import net.oschina.app.util.UIHelper; -import net.oschina.app.util.XmlUtils; - -import org.kymjs.kjframe.Core; - -import java.io.ByteArrayInputStream; - -import butterknife.InjectView; -import cz.msebera.android.httpclient.Header; - -/** - * 摇一摇界面 - * Created by 火蚁 on 15/5/28. - */ -public class ShakeActivity extends BaseActivity implements SensorEventListener { - - @InjectView(R.id.shake_img) - ImageView mImgShake; - - @InjectView(R.id.progress) - ProgressBar mProgress; - @InjectView(R.id.shake_bottom) - LinearLayout mLayoutBottom; - @InjectView(R.id.iv_face) - ImageView mImgHead; - @InjectView(R.id.tv_title) - TextView mTvTitle; - @InjectView(R.id.tv_description) - TextView mTvDetail; - @InjectView(R.id.tv_author) - TextView mTvAuthor; - @InjectView(R.id.tv_comment_count) - TextView mTvCommentCount; - @InjectView(R.id.tv_time) - TextView mTvDate; - - private SensorManager sensorManager = null; - private Sensor sensor; - private Vibrator vibrator = null; - - private boolean isRequest = false; - - private float lastX; - private float lastY; - private float lastZ; - private long lastUpdateTime; - private static final int SPEED_SHRESHOLD = 45;// 这个值越大需要越大的力气来摇晃手机 - private static final int UPTATE_INTERVAL_TIME = 50; - - @Override - protected boolean hasBackButton() { - return true; - } - - @Override - protected int getLayoutId() { - return R.layout.activity_shake; - } - - @Override - public void initView() { - - } - - /** - * 摇动手机成功后调用 - */ - private void onShake() { - isRequest = true; - mProgress.setVisibility(View.VISIBLE); - Animation anim = KJAnimations.shakeAnimation(mImgShake.getLeft()); - anim.setAnimationListener(new Animation.AnimationListener() { - - @Override - public void onAnimationStart(Animation animation) { - } - - @Override - public void onAnimationRepeat(Animation animation) { - } - - @Override - public void onAnimationEnd(Animation animation) { - OSChinaApi.shake(new AsyncHttpResponseHandler() { - @Override - public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { - isRequest = false; - final ShakeObject obj = XmlUtils.toBean( - ShakeObject.class, new ByteArrayInputStream( - arg2)); - if (obj != null) { - if (StringUtils.isEmpty(obj.getAuthor()) - && StringUtils.isEmpty(obj - .getCommentCount()) - && StringUtils.isEmpty(obj.getPubDate())) { - jokeToast(); - } else { - mLayoutBottom.setVisibility(View.VISIBLE); - mLayoutBottom - .setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - UIHelper.showUrlShake(ShakeActivity.this, obj); - } - }); - Core.getKJBitmap().displayWithLoadBitmap(mImgHead, - obj.getImage(), R.drawable.widget_dface); - mTvTitle.setText(obj.getTitle()); - mTvDetail.setText(obj.getDetail()); - mTvAuthor.setText(obj.getAuthor()); - TypefaceUtils.setTypeface(mTvAuthor); - TypefaceUtils.setTypeFaceWithText(mTvCommentCount, R.string - .fa_comment, obj.getCommentCount() + ""); - TypefaceUtils.setTypeFaceWithText(mTvDate, R.string.fa_clock_o, - StringUtils.friendly_time(obj.getPubDate())); - } - } else { - jokeToast(); - } - } - - @Override - public void onFailure(int arg0, Header[] arg1, byte[] arg2, - Throwable arg3) { - isRequest = false; - jokeToast(); - } - - @Override - public void onFinish() { - super.onFinish(); - if (mProgress != null) { - mProgress.setVisibility(View.GONE); - } - } - }); - } - }); - mImgShake.startAnimation(anim); - } - - private void jokeToast() { - AppContext.showToast("红薯跟你开了个玩笑"); - } - - @Override - public void onPause() { - super.onPause(); - sensorManager.unregisterListener(this); - } - - @Override - public void onResume() { - super.onResume(); - if (sensorManager != null) { - sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); - } - if (sensor != null) { - sensorManager.registerListener(this, sensor, - SensorManager.SENSOR_DELAY_GAME); - } - } - - @Override - public void onSensorChanged(SensorEvent event) { - long currentUpdateTime = System.currentTimeMillis(); - long timeInterval = currentUpdateTime - lastUpdateTime; - if (timeInterval < UPTATE_INTERVAL_TIME) { - return; - } - lastUpdateTime = currentUpdateTime; - - float x = event.values[0]; - float y = event.values[1]; - float z = event.values[2]; - - float deltaX = x - lastX; - float deltaY = y - lastY; - float deltaZ = z - lastZ; - - lastX = x; - lastY = y; - lastZ = z; - - double speed = (Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ - * deltaZ) / timeInterval) * 100; - if (speed >= SPEED_SHRESHOLD && !isRequest) { - mLayoutBottom.setVisibility(View.GONE); - vibrator.vibrate(300); - onShake(); - } - } - - @Override - public void onAccuracyChanged(Sensor sensor, int i) { - - } - - @Override - public void initData() { - sensorManager = (SensorManager) this - .getSystemService(Context.SENSOR_SERVICE); - vibrator = (Vibrator) this.getSystemService(Service.VIBRATOR_SERVICE); - } - - @Override - public void onClick(View view) { - - } -} diff --git a/app/src/main/java/net/oschina/app/ui/ShareDialog.java b/app/src/main/java/net/oschina/app/ui/ShareDialog.java index e76a1229e4c038c0fbbe69c9e1b93a543dccdb78..46964d09925f6d740bc8213da4624059fd5bb838 100644 --- a/app/src/main/java/net/oschina/app/ui/ShareDialog.java +++ b/app/src/main/java/net/oschina/app/ui/ShareDialog.java @@ -10,23 +10,8 @@ import android.view.Gravity; import android.view.View; import android.view.WindowManager; -import com.umeng.socialize.bean.SHARE_MEDIA; -import com.umeng.socialize.bean.ShareType; -import com.umeng.socialize.controller.UMServiceFactory; -import com.umeng.socialize.controller.UMSocialService; -import com.umeng.socialize.controller.listener.SocializeListeners; -import com.umeng.socialize.exception.SocializeException; -import com.umeng.socialize.media.UMImage; -import com.umeng.socialize.sso.SinaSsoHandler; -import com.umeng.socialize.sso.UMQQSsoHandler; -import com.umeng.socialize.utils.OauthHelper; -import com.umeng.socialize.weixin.controller.UMWXHandler; -import com.umeng.socialize.weixin.media.CircleShareContent; -import com.umeng.socialize.weixin.media.WeiXinShareContent; - import net.oschina.app.AppContext; import net.oschina.app.R; -import net.oschina.app.bean.Constants; import net.oschina.app.ui.dialog.CommonDialog; import net.oschina.app.util.TDevice; @@ -34,18 +19,16 @@ import net.oschina.app.util.TDevice; * 分享界面dialog * * @author kymjs - * */ public class ShareDialog extends CommonDialog implements - android.view.View.OnClickListener { + android.view.View.OnClickListener { private Context context; private String title; private String content; private String link; - final UMSocialService mController = UMServiceFactory - .getUMSocialService("com.umeng.share"); + // final UMSocialService mController = UMServiceFactory.getUMSocialService("com.umeng.share"); private ShareDialog(Context context, boolean flag, OnCancelListener listener) { super(context, flag, listener); @@ -118,7 +101,7 @@ public class ShareDialog extends CommonDialog implements TDevice.copyTextToBoard(this.link); break; case R.id.ly_share_more_option: - TDevice.showSystemShareOption((Activity)this.context, + TDevice.showSystemShareOption((Activity) this.context, this.content, this.title); break; default: @@ -130,91 +113,90 @@ public class ShareDialog extends CommonDialog implements @SuppressWarnings("deprecation") private void shareToWeiChatCircle() { // 支持微信朋友圈 - UMWXHandler wxCircleHandler = new UMWXHandler(this.context, - Constants.WEICHAT_APPID); - wxCircleHandler.setToCircle(true); - wxCircleHandler.addToSocialSDK(); + //UMWXHandler wxCircleHandler = new UMWXHandler(this.context, Constants.WEICHAT_APPID); + // wxCircleHandler.setToCircle(true); + // wxCircleHandler.addToSocialSDK(); // 设置微信朋友圈分享内容 - CircleShareContent circleMedia = new CircleShareContent(); - circleMedia.setShareContent(this.content); + // CircleShareContent circleMedia = new CircleShareContent(); + // circleMedia.setShareContent(this.content); // 设置朋友圈title - circleMedia.setTitle(this.title); - circleMedia.setShareImage(getShareImg()); - circleMedia.setTargetUrl(this.link); - mController.setShareMedia(circleMedia); - mController.postShare(this.context, SHARE_MEDIA.WEIXIN_CIRCLE, null); + //circleMedia.setTitle(this.title); + // circleMedia.setShareImage(getShareImg()); + // circleMedia.setTargetUrl(this.link); + // mController.setShareMedia(circleMedia); + // mController.postShare(this.context, SHARE_MEDIA.WEIXIN_CIRCLE, null); } @SuppressWarnings("deprecation") private void shareToWeiChat() { // 添加微信平台 - UMWXHandler wxHandler = new UMWXHandler(this.context, - Constants.WEICHAT_APPID); - wxHandler.addToSocialSDK(); + //UMWXHandler wxHandler = new UMWXHandler(this.context,Constants.WEICHAT_APPID); + // wxHandler.addToSocialSDK(); // 设置微信好友分享内容 - WeiXinShareContent weixinContent = new WeiXinShareContent(); + //WeiXinShareContent weixinContent = new WeiXinShareContent(); // 设置分享文字 - weixinContent.setShareContent(this.content); + // weixinContent.setShareContent(this.content); // 设置title - weixinContent.setTitle(this.title); + // weixinContent.setTitle(this.title); // 设置分享内容跳转URL - weixinContent.setTargetUrl(this.link); + // weixinContent.setTargetUrl(this.link); // 设置分享图片 - weixinContent.setShareImage(getShareImg()); - mController.setShareMedia(weixinContent); - mController.postShare(this.context, SHARE_MEDIA.WEIXIN, null); + // weixinContent.setShareImage(getShareImg()); + // mController.setShareMedia(weixinContent); + // mController.postShare(this.context, SHARE_MEDIA.WEIXIN, null); } private void shareToSinaWeibo() { // 设置新浪微博SSO handler - SinaSsoHandler sinaSsoHandler = new SinaSsoHandler(); - sinaSsoHandler.setTargetUrl(this.link); - mController.setShareType(ShareType.SHAKE); - mController.setShareContent(this.content + " " + this.link); - mController.setShareImage(getShareImg()); - mController.getConfig().setSsoHandler(sinaSsoHandler); - - if (OauthHelper.isAuthenticated(this.context, SHARE_MEDIA.SINA)) { - mController.directShare(this.context, SHARE_MEDIA.SINA, null); - } else { - mController.doOauthVerify(this.context, SHARE_MEDIA.SINA, - new SocializeListeners.UMAuthListener() { - - @Override - public void onStart(SHARE_MEDIA arg0) { - } - - @Override - public void onError(SocializeException arg0, - SHARE_MEDIA arg1) { - } - - @Override - public void onComplete(Bundle arg0, SHARE_MEDIA arg1) { - mController.directShare(ShareDialog.this.context, SHARE_MEDIA.SINA, null); - } - - @Override - public void onCancel(SHARE_MEDIA arg0) {} - }); - } + // SinaSsoHandler sinaSsoHandler = new SinaSsoHandler(); + // sinaSsoHandler.setTargetUrl(this.link); + // mController.setShareType(ShareType.SHAKE); + // mController.setShareContent(this.content + " " + this.link); + // mController.setShareImage(getShareImg()); + // mController.getConfig().setSsoHandler(sinaSsoHandler); + + //if (OauthHelper.isAuthenticated(this.context, SHARE_MEDIA.SINA)) { + // mController.directShare(this.context, SHARE_MEDIA.SINA, null); + // } else { + // mController.doOauthVerify(this.context, SHARE_MEDIA.SINA, + // new SocializeListeners.UMAuthListener() { +// +// @Override +// public void onStart(SHARE_MEDIA arg0) { +// } +// +// @Override +// public void onError(SocializeException arg0, +// SHARE_MEDIA arg1) { +// } +// +// @Override +// public void onComplete(Bundle arg0, SHARE_MEDIA arg1) { +// mController.directShare(ShareDialog.this.context, SHARE_MEDIA.SINA, +// null); +// } +// +// @Override +// public void onCancel(SHARE_MEDIA arg0) { +// } +// }); +// } } private void shareToQQ() { - UMQQSsoHandler qqSsoHandler = new UMQQSsoHandler((Activity)this.context, - Constants.QQ_APPID, Constants.QQ_APPKEY); - qqSsoHandler.setTargetUrl(this.link); - qqSsoHandler.setTitle(this.title); - qqSsoHandler.addToSocialSDK(); - mController.setShareContent(this.content); - mController.setShareImage(getShareImg()); - mController.postShare(this.context, SHARE_MEDIA.QQ, null); +// UMQQSsoHandler qqSsoHandler = new UMQQSsoHandler((Activity) this.context, + // Constants.QQ_APPID, Constants.QQ_APPKEY); +// qqSsoHandler.setTargetUrl(this.link); +// qqSsoHandler.setTitle(this.title); +// qqSsoHandler.addToSocialSDK(); +// mController.setShareContent(this.content); +// mController.setShareImage(getShareImg()); +// mController.postShare(this.context, SHARE_MEDIA.QQ, null); } - private UMImage getShareImg() { - UMImage img = new UMImage(this.context, R.drawable.ic_share); - return img; - } +// private UMImage getShareImg() { + // return new UMImage(this.context, R.mipmap.ic_share); +// } private boolean checkCanShare() { boolean canShare = true; @@ -223,4 +205,8 @@ public class ShareDialog extends CommonDialog implements } return canShare; } + +// public UMSocialService getController() { +// return mController; +// } } diff --git a/app/src/main/java/net/oschina/app/ui/SimpleBackActivity.java b/app/src/main/java/net/oschina/app/ui/SimpleBackActivity.java index d44d97e87fb5a94d8195237c1d2497b3b673f8b5..27cd0452f2c037b2a27541ce3a6575eccdf55255 100644 --- a/app/src/main/java/net/oschina/app/ui/SimpleBackActivity.java +++ b/app/src/main/java/net/oschina/app/ui/SimpleBackActivity.java @@ -1,27 +1,24 @@ package net.oschina.app.ui; +import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; import android.text.Editable; import android.view.KeyEvent; -import android.view.Menu; -import android.view.MenuItem; import android.view.View; +import android.view.inputmethod.InputMethodManager; import net.oschina.app.R; import net.oschina.app.base.BaseActivity; import net.oschina.app.base.BaseFragment; import net.oschina.app.bean.SimpleBackPage; import net.oschina.app.emoji.OnSendClickListener; -import net.oschina.app.fragment.MessageDetailFragment; -import net.oschina.app.fragment.TweetPubFragment; -import net.oschina.app.fragment.TweetsFragment; -import net.oschina.app.util.UIHelper; import java.lang.ref.WeakReference; + public class SimpleBackActivity extends BaseActivity implements OnSendClickListener { @@ -31,6 +28,17 @@ public class SimpleBackActivity extends BaseActivity implements protected WeakReference mFragment; protected int mPageValue = -1; + @Override + public void startActivity(Intent intent) { + View view = getCurrentFocus(); + if (view != null) { + view.clearFocus(); + InputMethodManager manager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + manager.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); + } + super.startActivity(intent); + } + @Override protected int getLayoutId() { return R.layout.activity_simple_fragment; @@ -44,21 +52,20 @@ public class SimpleBackActivity extends BaseActivity implements @Override protected void init(Bundle savedInstanceState) { super.init(savedInstanceState); + Intent intent = getIntent(); if (mPageValue == -1) { - mPageValue = getIntent().getIntExtra(BUNDLE_KEY_PAGE, 0); + mPageValue = intent.getIntExtra(BUNDLE_KEY_PAGE, 0); } initFromIntent(mPageValue, getIntent()); } protected void initFromIntent(int pageValue, Intent data) { if (data == null) { - throw new RuntimeException( - "you must provide a page info to display"); + throw new RuntimeException("you must provide a page info to display"); } SimpleBackPage page = SimpleBackPage.getPageByValue(pageValue); if (page == null) { - throw new IllegalArgumentException("can not find page by value:" - + pageValue); + throw new IllegalArgumentException("can not find page by value:" + pageValue); } setActionBarTitle(page.getTitle()); @@ -76,7 +83,7 @@ public class SimpleBackActivity extends BaseActivity implements trans.replace(R.id.container, fragment, TAG); trans.commitAllowingStateLoss(); - mFragment = new WeakReference(fragment); + mFragment = new WeakReference<>(fragment); } catch (Exception e) { e.printStackTrace(); throw new IllegalArgumentException( @@ -84,59 +91,6 @@ public class SimpleBackActivity extends BaseActivity implements } } - @Override - protected void onResume() { - super.onResume(); - if (mFragment.get() instanceof TweetsFragment) { - setActionBarTitle("话题"); - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.public_menu_send: - if (mFragment.get() instanceof TweetsFragment) { - sendTopic(); - } else { - return super.onOptionsItemSelected(item); - } - break; - case R.id.chat_friend_home: - if (mFragment.get() instanceof MessageDetailFragment) { - ((MessageDetailFragment)mFragment.get()).showFriendUserCenter(); - } else { - return super.onOptionsItemSelected(item); - } - break; - default: - break; - } - return super.onOptionsItemSelected(item); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - if (mFragment.get() instanceof TweetsFragment) { - getMenuInflater().inflate(R.menu.pub_topic_menu, menu); - }else if (mFragment.get() instanceof MessageDetailFragment){ - getMenuInflater().inflate(R.menu.chat_menu, menu); - } - return super.onCreateOptionsMenu(menu); - } - - /** - * 发送话题 - */ - private void sendTopic() { - Bundle bundle = new Bundle(); - bundle.putInt(TweetPubFragment.ACTION_TYPE, - TweetPubFragment.ACTION_TYPE_TOPIC); - bundle.putString("tweet_topic", "#" - + ((TweetsFragment) mFragment.get()).getTopic() + "# "); - UIHelper.showTweetActivity(this, SimpleBackPage.TWEET_PUB, bundle); - } - @Override public void onBackPressed() { if (mFragment != null && mFragment.get() != null @@ -165,22 +119,23 @@ public class SimpleBackActivity extends BaseActivity implements } @Override - public void onClick(View v) {} + public void onClick(View v) { + } @Override - public void initView() {} + public void initView() { + } @Override - public void initData() {} + public void initData() { + } @Override public void onClickSendButton(Editable str) { - if (mFragment.get() instanceof MessageDetailFragment) { - ((OnSendClickListener) mFragment.get()).onClickSendButton(str); - ((MessageDetailFragment) mFragment.get()).emojiFragment.clean(); - } + } @Override - public void onClickFlagButton() {} + public void onClickFlagButton() { + } } diff --git a/app/src/main/java/net/oschina/app/ui/TweetActivity.java b/app/src/main/java/net/oschina/app/ui/TweetActivity.java deleted file mode 100644 index e3f2c329109807a4bf615ae9b4d5853eff3b968c..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/ui/TweetActivity.java +++ /dev/null @@ -1,103 +0,0 @@ -package net.oschina.app.ui; - -import java.util.ArrayList; - -import net.oschina.app.bean.SimpleBackPage; -import net.oschina.app.fragment.TweetPubFragment; -import android.content.Intent; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.provider.MediaStore; - -/** - * 对动弹界面的一个封装,用于相应系统分享 - * - * @author kymjs (https://github.com/kymjs) - * - */ -public class TweetActivity extends SimpleBackActivity { - private TweetPubFragment currentFragment; - - public static String FROM_KEY = "image_shared_key"; - - @Override - protected void onCreate(Bundle savedInstanceState) { - Intent intent = getIntent(); - if (intent.getIntExtra(FROM_KEY, -1) != 1) { - mPageValue = SimpleBackPage.TWEET_PUB.getValue(); - } - super.onCreate(savedInstanceState); - respondExternal(intent); - } - - /** - * 响应从图片分享进入的事件 - * - * @param intent - */ - private void respondExternal(Intent intent) { - currentFragment = (TweetPubFragment) mFragment.get(); - - String action = intent.getAction(); - String type = intent.getType(); - - if (Intent.ACTION_SEND.equals(action) && type != null) { - if ("text/plain".equals(type)) { - handleSendText(intent); // Handle text being sent - } else if (type.startsWith("image/")) { - handleSendImage(intent); // Handle single image being sent - } - } else if (Intent.ACTION_SEND_MULTIPLE.equals(action) && type != null) { - if (type.startsWith("image/")) { - handleSendMultipleImages(intent); // Handle multiple images - // being sent - } - } else { - // Handle other intents, such as being started from the home screen - } - } - - void handleSendText(Intent intent) { - String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT); - String sharedTitle = intent.getStringExtra(Intent.EXTRA_TITLE); - if (sharedText != null) { - currentFragment.setContentText(sharedText); - } - } - - void handleSendImage(Intent intent) { - Uri imageUri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM); - if (imageUri != null) { - currentFragment.setContentImage(getAbsoluteImagePath(imageUri)); - } - } - - void handleSendMultipleImages(Intent intent) { - ArrayList imageUris = intent - .getParcelableArrayListExtra(Intent.EXTRA_STREAM); - if (imageUris != null) { - currentFragment.setContentImage(getAbsoluteImagePath(imageUris - .get(0))); - } - } - - protected String getAbsoluteImagePath(Uri uri) { - // can post image - String[] proj = { MediaStore.Images.Media.DATA }; - Cursor cursor = managedQuery(uri, proj, // Which columns to return - null, // WHERE clause; which rows to return (all rows) - null, // WHERE clause selection arguments (none) - null); // Order-by clause (ascending by name) - if (cursor != null) { - int column_index = cursor - .getColumnIndexOrThrow(MediaStore.Images.Media.DATA); - cursor.moveToFirst(); - - return cursor.getString(column_index); - } else { - // 如果游标为空说明获取的已经是绝对路径了 - return uri.getPath(); - } - } -} diff --git a/app/src/main/java/net/oschina/app/ui/dialog/CommonDialog.java b/app/src/main/java/net/oschina/app/ui/dialog/CommonDialog.java index 914a351a9c5d775821080f269f2351d14f0498d8..19556c90b1711350e4822f31049426e31073293a 100644 --- a/app/src/main/java/net/oschina/app/ui/dialog/CommonDialog.java +++ b/app/src/main/java/net/oschina/app/ui/dialog/CommonDialog.java @@ -111,7 +111,7 @@ public class CommonDialog extends Dialog { protected void onCreate(Bundle bundle) { super.onCreate(bundle); if (TDevice.isTablet()) { - int maxWidth = (int) TDevice.dpToPixel(360f); + int maxWidth = (int) TDevice.dp2px(360f); if (maxWidth < TDevice.getScreenWidth()) { WindowManager.LayoutParams params = getWindow().getAttributes(); params.width = maxWidth; diff --git a/app/src/main/java/net/oschina/app/ui/dialog/CommonToast.java b/app/src/main/java/net/oschina/app/ui/dialog/CommonToast.java index 3099c91fab5812ea2b3e0c30047f34b015128251..8874c852b25f2b4b3a4dfedc41c7900d80e8d4c8 100644 --- a/app/src/main/java/net/oschina/app/ui/dialog/CommonToast.java +++ b/app/src/main/java/net/oschina/app/ui/dialog/CommonToast.java @@ -65,7 +65,7 @@ public class CommonToast { FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(-2, -2); params.gravity = i; - int j = (int) TDevice.dpToPixel(16F); + int j = (int) TDevice.dp2px(16F); params.setMargins(j, j, j, j); _toastVw.setLayoutParams(params); } diff --git a/app/src/main/java/net/oschina/app/ui/empty/EmptyLayout.java b/app/src/main/java/net/oschina/app/ui/empty/EmptyLayout.java index d48c75197c7d56d7cc7fcf72bce4388487effe5e..b7b20fa8507dd768034081eee335547bd386c946 100644 --- a/app/src/main/java/net/oschina/app/ui/empty/EmptyLayout.java +++ b/app/src/main/java/net/oschina/app/ui/empty/EmptyLayout.java @@ -1,16 +1,20 @@ package net.oschina.app.ui.empty; -import net.oschina.app.R; -import net.oschina.app.util.TDevice; import android.content.Context; +import android.graphics.drawable.ColorDrawable; import android.util.AttributeSet; +import android.view.LayoutInflater; import android.view.View; +import android.view.ViewGroup; import android.widget.ImageView; import android.widget.LinearLayout; -import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.TextView; +import net.oschina.app.R; +import net.oschina.app.util.TDevice; +import net.qiujuer.genius.ui.widget.Loading; + public class EmptyLayout extends LinearLayout implements android.view.View.OnClickListener {// , ISkinUIObserver { @@ -21,13 +25,12 @@ public class EmptyLayout extends LinearLayout implements public static final int NODATA_ENABLE_CLICK = 5; public static final int NO_LOGIN = 6; - private ProgressBar animProgress; + private Loading mLoading; private boolean clickEnable = true; private final Context context; public ImageView img; private android.view.View.OnClickListener listener; private int mErrorState; - private RelativeLayout mLayout; private String strNoDataContent = ""; private TextView tv; @@ -44,11 +47,10 @@ public class EmptyLayout extends LinearLayout implements } private void init() { - View view = View.inflate(context, R.layout.view_error_layout, null); + View view = LayoutInflater.from(getContext()).inflate(R.layout.view_error_layout, this, false); img = (ImageView) view.findViewById(R.id.img_error_layout); tv = (TextView) view.findViewById(R.id.tv_error_layout); - mLayout = (RelativeLayout) view.findViewById(R.id.pageerrLayout); - animProgress = (ProgressBar) view.findViewById(R.id.animProgress); + mLoading = (Loading) view.findViewById(R.id.animProgress); setBackgroundColor(-1); setOnClickListener(this); img.setOnClickListener(new View.OnClickListener() { @@ -117,17 +119,14 @@ public class EmptyLayout extends LinearLayout implements // tv.setTextColor(SkinsUtil.getColor(getContext(), "textcolor05")); } - public void setDayNight(boolean flag) {} - public void setErrorMessage(String msg) { tv.setText(msg); } /** * 新添设置背景 - * + * * @author 火蚁 2015-1-27 下午2:14:00 - * */ public void setErrorImag(int imgResource) { try { @@ -139,51 +138,56 @@ public class EmptyLayout extends LinearLayout implements public void setErrorType(int i) { setVisibility(View.VISIBLE); switch (i) { - case NETWORK_ERROR: - mErrorState = NETWORK_ERROR; - // img.setBackgroundDrawable(SkinsUtil.getDrawable(context,"pagefailed_bg")); - if (TDevice.hasInternet()) { - tv.setText(R.string.error_view_load_error_click_to_refresh); - img.setBackgroundResource(R.drawable.pagefailed_bg); - } else { - tv.setText(R.string.error_view_network_error_click_to_refresh); - img.setBackgroundResource(R.drawable.page_icon_network); - } - img.setVisibility(View.VISIBLE); - animProgress.setVisibility(View.GONE); - clickEnable = true; - break; - case NETWORK_LOADING: - mErrorState = NETWORK_LOADING; - // animProgress.setBackgroundDrawable(SkinsUtil.getDrawable(context,"loadingpage_bg")); - animProgress.setVisibility(View.VISIBLE); - img.setVisibility(View.GONE); - tv.setText(R.string.error_view_loading); - clickEnable = false; - break; - case NODATA: - mErrorState = NODATA; - // img.setBackgroundDrawable(SkinsUtil.getDrawable(context,"page_icon_empty")); - img.setBackgroundResource(R.drawable.page_icon_empty); - img.setVisibility(View.VISIBLE); - animProgress.setVisibility(View.GONE); - setTvNoDataContent(); - clickEnable = true; - break; - case HIDE_LAYOUT: - setVisibility(View.GONE); - break; - case NODATA_ENABLE_CLICK: - mErrorState = NODATA_ENABLE_CLICK; - img.setBackgroundResource(R.drawable.page_icon_empty); - // img.setBackgroundDrawable(SkinsUtil.getDrawable(context,"page_icon_empty")); - img.setVisibility(View.VISIBLE); - animProgress.setVisibility(View.GONE); - setTvNoDataContent(); - clickEnable = true; - break; - default: - break; + case NETWORK_ERROR: + mErrorState = NETWORK_ERROR; + // img.setBackgroundDrawable(SkinsUtil.getDrawable(context,"pagefailed_bg")); + if (TDevice.hasInternet()) { + tv.setText(R.string.error_view_load_error_click_to_refresh); + img.setBackgroundResource(R.mipmap.ic_tip_fail); + } else { + tv.setText(R.string.error_view_network_error_click_to_refresh); + img.setBackgroundResource(R.mipmap.page_icon_network); + } + img.setVisibility(View.VISIBLE); + mLoading.stop(); + mLoading.setVisibility(View.GONE); + clickEnable = true; + break; + case NETWORK_LOADING: + mErrorState = NETWORK_LOADING; + // mLoading.setBackgroundDrawable(SkinsUtil.getDrawable(context,"loadingpage_bg")); + mLoading.setVisibility(View.VISIBLE); + mLoading.start(); + img.setVisibility(View.GONE); + tv.setText(R.string.error_view_loading); + clickEnable = false; + break; + case NODATA: + mErrorState = NODATA; + // img.setBackgroundDrawable(SkinsUtil.getDrawable(context,"page_icon_empty")); + img.setBackgroundResource(R.mipmap.page_icon_empty); + img.setVisibility(View.VISIBLE); + mLoading.stop(); + mLoading.setVisibility(View.GONE); + setTvNoDataContent(); + clickEnable = true; + break; + case HIDE_LAYOUT: + mLoading.stop(); + setVisibility(View.GONE); + break; + case NODATA_ENABLE_CLICK: + mErrorState = NODATA_ENABLE_CLICK; + img.setBackgroundResource(R.mipmap.page_icon_empty); + // img.setBackgroundDrawable(SkinsUtil.getDrawable(context,"page_icon_empty")); + img.setVisibility(View.VISIBLE); + mLoading.stop(); + mLoading.setVisibility(View.GONE); + setTvNoDataContent(); + clickEnable = true; + break; + default: + break; } } diff --git a/app/src/main/java/net/oschina/app/util/CyptoUtils.java b/app/src/main/java/net/oschina/app/util/CyptoUtils.java deleted file mode 100644 index ee9d404882da5725adaf6fe016d8e524f81efc4c..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/util/CyptoUtils.java +++ /dev/null @@ -1,105 +0,0 @@ -package net.oschina.app.util; - -import java.security.InvalidAlgorithmParameterException; -import java.security.Key; -import java.security.spec.AlgorithmParameterSpec; - -import javax.crypto.Cipher; -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.DESKeySpec; -import javax.crypto.spec.IvParameterSpec; - -/** - * 加密解密工具包 - * @author Winter Lau - * @date 2011-12-26 - */ -public class CyptoUtils { - - public static final String ALGORITHM_DES = "DES/CBC/PKCS5Padding"; - - /** - * DES算法,加密 - * - * @param data 待加密字符串 - * @param key 加密私钥,长度不能够小于8位 - * @return 加密后的字节数组,一般结合Base64编码使用 - * @throws InvalidAlgorithmParameterException - * @throws Exception - */ - public static String encode(String key,String data) { - if(data == null) - return null; - try{ - DESKeySpec dks = new DESKeySpec(key.getBytes()); - SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); - //key的长度不能够小于8位字节 - Key secretKey = keyFactory.generateSecret(dks); - Cipher cipher = Cipher.getInstance(ALGORITHM_DES); - IvParameterSpec iv = new IvParameterSpec("12345678".getBytes()); - AlgorithmParameterSpec paramSpec = iv; - cipher.init(Cipher.ENCRYPT_MODE, secretKey,paramSpec); - byte[] bytes = cipher.doFinal(data.getBytes()); - return byte2hex(bytes); - }catch(Exception e){ - e.printStackTrace(); - return data; - } - } - - /** - * DES算法,解密 - * - * @param data 待解密字符串 - * @param key 解密私钥,长度不能够小于8位 - * @return 解密后的字节数组 - * @throws Exception 异常 - */ - public static String decode(String key,String data) { - if(data == null) - return null; - try { - DESKeySpec dks = new DESKeySpec(key.getBytes()); - SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); - //key的长度不能够小于8位字节 - Key secretKey = keyFactory.generateSecret(dks); - Cipher cipher = Cipher.getInstance(ALGORITHM_DES); - IvParameterSpec iv = new IvParameterSpec("12345678".getBytes()); - AlgorithmParameterSpec paramSpec = iv; - cipher.init(Cipher.DECRYPT_MODE, secretKey, paramSpec); - return new String(cipher.doFinal(hex2byte(data.getBytes()))); - } catch (Exception e){ - e.printStackTrace(); - return data; - } - } - - /** - * 二行制转字符串 - * @param b - * @return - */ - private static String byte2hex(byte[] b) { - StringBuilder hs = new StringBuilder(); - String stmp; - for (int n = 0; b!=null && n < b.length; n++) { - stmp = Integer.toHexString(b[n] & 0XFF); - if (stmp.length() == 1) - hs.append('0'); - hs.append(stmp); - } - return hs.toString().toUpperCase(); - } - - private static byte[] hex2byte(byte[] b) { - if((b.length%2)!=0) - throw new IllegalArgumentException(); - byte[] b2 = new byte[b.length/2]; - for (int n = 0; n < b.length; n+=2) { - String item = new String(b,n,2); - b2[n/2] = (byte)Integer.parseInt(item,16); - } - return b2; - } - -} diff --git a/app/src/main/java/net/oschina/app/util/DialogHelp.java b/app/src/main/java/net/oschina/app/util/DialogHelp.java deleted file mode 100644 index e3f47313f9581e8308e363249222bfe84857f90c..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/util/DialogHelp.java +++ /dev/null @@ -1,101 +0,0 @@ -package net.oschina.app.util; - -import android.app.ProgressDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.support.v7.app.AlertDialog; -import android.text.Html; -import android.text.TextUtils; - -/** - * 对话框辅助类 - * Created by 火蚁 on 15/6/19. - */ -public class DialogHelp { - - /*** - * 获取一个dialog - * @param context - * @return - */ - public static AlertDialog.Builder getDialog(Context context) { - AlertDialog.Builder builder = new AlertDialog.Builder(context); - return builder; - } - - /*** - * 获取一个耗时等待对话框 - * @param context - * @param message - * @return - */ - public static ProgressDialog getWaitDialog(Context context, String message) { - ProgressDialog waitDialog = new ProgressDialog(context); - if (!TextUtils.isEmpty(message)) { - waitDialog.setMessage(message); - } - return waitDialog; - } - - /*** - * 获取一个信息对话框,注意需要自己手动调用show方法显示 - * @param context - * @param message - * @param onClickListener - * @return - */ - public static AlertDialog.Builder getMessageDialog(Context context, String message, DialogInterface.OnClickListener onClickListener) { - AlertDialog.Builder builder = getDialog(context); - builder.setMessage(message); - builder.setPositiveButton("确定", onClickListener); - return builder; - } - - public static AlertDialog.Builder getMessageDialog(Context context, String message) { - return getMessageDialog(context, message, null); - } - - public static AlertDialog.Builder getConfirmDialog(Context context, String message, DialogInterface.OnClickListener onClickListener) { - AlertDialog.Builder builder = getDialog(context); - builder.setMessage(Html.fromHtml(message)); - builder.setPositiveButton("确定", onClickListener); - builder.setNegativeButton("取消", null); - return builder; - } - - public static AlertDialog.Builder getConfirmDialog(Context context, String message, DialogInterface.OnClickListener onOkClickListener, DialogInterface.OnClickListener onCancleClickListener) { - AlertDialog.Builder builder = getDialog(context); - builder.setMessage(message); - builder.setPositiveButton("确定", onOkClickListener); - builder.setNegativeButton("取消", onCancleClickListener); - return builder; - } - - public static AlertDialog.Builder getSelectDialog(Context context, String title, String[] arrays, DialogInterface.OnClickListener onClickListener) { - AlertDialog.Builder builder = getDialog(context); - builder.setItems(arrays, onClickListener); - if (!TextUtils.isEmpty(title)) { - builder.setTitle(title); - } - builder.setPositiveButton("取消", null); - return builder; - } - - public static AlertDialog.Builder getSelectDialog(Context context, String[] arrays, DialogInterface.OnClickListener onClickListener) { - return getSelectDialog(context, "", arrays, onClickListener); - } - - public static AlertDialog.Builder getSingleChoiceDialog(Context context, String title, String[] arrays, int selectIndex, DialogInterface.OnClickListener onClickListener) { - AlertDialog.Builder builder = getDialog(context); - builder.setSingleChoiceItems(arrays, selectIndex, onClickListener); - if (!TextUtils.isEmpty(title)) { - builder.setTitle(title); - } - builder.setNegativeButton("取消", null); - return builder; - } - - public static AlertDialog.Builder getSingleChoiceDialog(Context context, String[] arrays, int selectIndex, DialogInterface.OnClickListener onClickListener) { - return getSingleChoiceDialog(context, "", arrays, selectIndex, onClickListener); - } -} diff --git a/app/src/main/java/net/oschina/app/util/FileUtil.java b/app/src/main/java/net/oschina/app/util/FileUtil.java index 5b477d1f974fa113ac9522ea4d363177bb1a7916..9dd18f8430b1f11aa757a1cde13f003ea9230ab8 100644 --- a/app/src/main/java/net/oschina/app/util/FileUtil.java +++ b/app/src/main/java/net/oschina/app/util/FileUtil.java @@ -1,5 +1,10 @@ package net.oschina.app.util; +import android.content.Context; +import android.os.Environment; +import android.os.StatFs; +import android.util.Log; + import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; @@ -10,625 +15,625 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import android.content.Context; -import android.os.Environment; -import android.os.StatFs; -import android.util.Log; - /** * 文件操作工具包 - * + * * @author liux (http://my.oschina.net/liux) * @version 1.0 * @created 2012-3-21 */ public class FileUtil { /** - * 写文本文件 在Android系统中,文件保存在 /data/data/PACKAGE_NAME/files 目录下 - * - * @param context - * @param msg - */ - public static void write(Context context, String fileName, String content) { - if (content == null) - content = ""; - - try { - FileOutputStream fos = context.openFileOutput(fileName, - Context.MODE_PRIVATE); - fos.write(content.getBytes()); - - fos.close(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - /** - * 读取文本文件 - * - * @param context - * @param fileName - * @return - */ - public static String read(Context context, String fileName) { - try { - FileInputStream in = context.openFileInput(fileName); - return readInStream(in); - } catch (Exception e) { - e.printStackTrace(); - } - return ""; - } - - public static String readInStream(InputStream inStream) { - try { - ByteArrayOutputStream outStream = new ByteArrayOutputStream(); - byte[] buffer = new byte[512]; - int length = -1; - while ((length = inStream.read(buffer)) != -1) { - outStream.write(buffer, 0, length); - } - - outStream.close(); - inStream.close(); - return outStream.toString(); - } catch (IOException e) { - Log.i("FileTest", e.getMessage()); - } - return null; - } - - public static File createFile(String folderPath, String fileName) { - File destDir = new File(folderPath); - if (!destDir.exists()) { - destDir.mkdirs(); - } - return new File(folderPath, fileName + fileName); - } - - /** - * 向手机写图片 - * - * @param buffer - * @param folder - * @param fileName - * @return - */ - public static boolean writeFile(byte[] buffer, String folder, - String fileName) { - boolean writeSucc = false; - - boolean sdCardExist = Environment.getExternalStorageState().equals( - android.os.Environment.MEDIA_MOUNTED); - - String folderPath = ""; - if (sdCardExist) { - folderPath = Environment.getExternalStorageDirectory() - + File.separator + folder + File.separator; - } else { - writeSucc = false; - } - - File fileDir = new File(folderPath); - if (!fileDir.exists()) { - fileDir.mkdirs(); - } - - File file = new File(folderPath + fileName); - FileOutputStream out = null; - try { - out = new FileOutputStream(file); - out.write(buffer); - writeSucc = true; - } catch (Exception e) { - e.printStackTrace(); - } finally { - try { - out.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - return writeSucc; - } - - /** - * 根据文件绝对路径获取文件名 - * - * @param filePath - * @return - */ - public static String getFileName(String filePath) { - if (StringUtils.isEmpty(filePath)) - return ""; - return filePath.substring(filePath.lastIndexOf(File.separator) + 1); - } - - /** - * 根据文件的绝对路径获取文件名但不包含扩展名 - * - * @param filePath - * @return - */ - public static String getFileNameNoFormat(String filePath) { - if (StringUtils.isEmpty(filePath)) { - return ""; - } - int point = filePath.lastIndexOf('.'); - return filePath.substring(filePath.lastIndexOf(File.separator) + 1, - point); - } - - /** - * 获取文件扩展名 - * - * @param fileName - * @return - */ - public static String getFileFormat(String fileName) { - if (StringUtils.isEmpty(fileName)) - return ""; - - int point = fileName.lastIndexOf('.'); - return fileName.substring(point + 1); - } - - /** - * 获取文件大小 - * - * @param filePath - * @return - */ - public static long getFileSize(String filePath) { - long size = 0; - - File file = new File(filePath); - if (file != null && file.exists()) { - size = file.length(); - } - return size; - } - - /** - * 获取文件大小 - * - * @param size - * 字节 - * @return - */ - public static String getFileSize(long size) { - if (size <= 0) - return "0"; - java.text.DecimalFormat df = new java.text.DecimalFormat("##.##"); - float temp = (float) size / 1024; - if (temp >= 1024) { - return df.format(temp / 1024) + "M"; - } else { - return df.format(temp) + "K"; - } - } - - /** - * 转换文件大小 - * - * @param fileS - * @return B/KB/MB/GB - */ - public static String formatFileSize(long fileS) { - java.text.DecimalFormat df = new java.text.DecimalFormat("#.00"); - String fileSizeString = ""; - if (fileS < 1024) { - fileSizeString = df.format((double) fileS) + "B"; - } else if (fileS < 1048576) { - fileSizeString = df.format((double) fileS / 1024) + "KB"; - } else if (fileS < 1073741824) { - fileSizeString = df.format((double) fileS / 1048576) + "MB"; - } else { - fileSizeString = df.format((double) fileS / 1073741824) + "G"; - } - return fileSizeString; - } - - /** - * 获取目录文件大小 - * - * @param dir - * @return - */ - public static long getDirSize(File dir) { - if (dir == null) { - return 0; - } - if (!dir.isDirectory()) { - return 0; - } - long dirSize = 0; - File[] files = dir.listFiles(); - for (File file : files) { - if (file.isFile()) { - dirSize += file.length(); - } else if (file.isDirectory()) { - dirSize += file.length(); - dirSize += getDirSize(file); // 递归调用继续统计 - } - } - return dirSize; - } - - /** - * 获取目录文件个数 - * - * @param emojiFragment - * @return - */ - public long getFileList(File dir) { - long count = 0; - File[] files = dir.listFiles(); - count = files.length; - for (File file : files) { - if (file.isDirectory()) { - count = count + getFileList(file);// 递归 - count--; - } - } - return count; - } - - public static byte[] toBytes(InputStream in) throws IOException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - int ch; - while ((ch = in.read()) != -1) { - out.write(ch); - } - byte buffer[] = out.toByteArray(); - out.close(); - return buffer; - } - - /** - * 检查文件是否存在 - * - * @param name - * @return - */ - public static boolean checkFileExists(String name) { - boolean status; - if (!name.equals("")) { - File path = Environment.getExternalStorageDirectory(); - File newPath = new File(path.toString() + name); - status = newPath.exists(); - } else { - status = false; - } - return status; - } - - /** - * 检查路径是否存在 - * - * @param path - * @return - */ - public static boolean checkFilePathExists(String path) { - return new File(path).exists(); - } - - /** - * 计算SD卡的剩余空间 - * - * @return 返回-1,说明没有安装sd卡 - */ - public static long getFreeDiskSpace() { - String status = Environment.getExternalStorageState(); - long freeSpace = 0; - if (status.equals(Environment.MEDIA_MOUNTED)) { - try { - File path = Environment.getExternalStorageDirectory(); - StatFs stat = new StatFs(path.getPath()); - long blockSize = stat.getBlockSize(); - long availableBlocks = stat.getAvailableBlocks(); - freeSpace = availableBlocks * blockSize / 1024; - } catch (Exception e) { - e.printStackTrace(); - } - } else { - return -1; - } - return (freeSpace); - } - - /** - * 新建目录 - * - * @param directoryName - * @return - */ - public static boolean createDirectory(String directoryName) { - boolean status; - if (!directoryName.equals("")) { - File path = Environment.getExternalStorageDirectory(); - File newPath = new File(path.toString() + directoryName); - status = newPath.mkdir(); - status = true; - } else - status = false; - return status; - } - - /** - * 检查是否安装SD卡 - * - * @return - */ - public static boolean checkSaveLocationExists() { - String sDCardStatus = Environment.getExternalStorageState(); - boolean status; - if (sDCardStatus.equals(Environment.MEDIA_MOUNTED)) { - status = true; - } else - status = false; - return status; - } - - /** - * 检查是否安装外置的SD卡 - * - * @return - */ - public static boolean checkExternalSDExists() { - - Map evn = System.getenv(); - return evn.containsKey("SECONDARY_STORAGE"); - } - - /** - * 删除目录(包括:目录里的所有文件) - * - * @param fileName - * @return - */ - public static boolean deleteDirectory(String fileName) { - boolean status; - SecurityManager checker = new SecurityManager(); - - if (!fileName.equals("")) { - - File path = Environment.getExternalStorageDirectory(); - File newPath = new File(path.toString() + fileName); - checker.checkDelete(newPath.toString()); - if (newPath.isDirectory()) { - String[] listfile = newPath.list(); - try { - for (int i = 0; i < listfile.length; i++) { - File deletedFile = new File(newPath.toString() + "/" - + listfile[i].toString()); - deletedFile.delete(); - } - newPath.delete(); - Log.i("DirectoryManager deleteDirectory", fileName); - status = true; - } catch (Exception e) { - e.printStackTrace(); - status = false; - } - - } else - status = false; - } else - status = false; - return status; - } - - /** - * 删除文件 - * - * @param fileName - * @return - */ - public static boolean deleteFile(String fileName) { - boolean status; - SecurityManager checker = new SecurityManager(); - - if (!fileName.equals("")) { - - File path = Environment.getExternalStorageDirectory(); - File newPath = new File(path.toString() + fileName); - checker.checkDelete(newPath.toString()); - if (newPath.isFile()) { - try { - Log.i("DirectoryManager deleteFile", fileName); - newPath.delete(); - status = true; - } catch (SecurityException se) { - se.printStackTrace(); - status = false; - } - } else - status = false; - } else - status = false; - return status; - } - - /** - * 删除空目录 - * - * 返回 0代表成功 ,1 代表没有删除权限, 2代表不是空目录,3 代表未知错误 - * - * @return - */ - public static int deleteBlankPath(String path) { - File f = new File(path); - if (!f.canWrite()) { - return 1; - } - if (f.list() != null && f.list().length > 0) { - return 2; - } - if (f.delete()) { - return 0; - } - return 3; - } - - /** - * 重命名 - * - * @param oldName - * @param newName - * @return - */ - public static boolean reNamePath(String oldName, String newName) { - File f = new File(oldName); - return f.renameTo(new File(newName)); - } - - /** - * 删除文件 - * - * @param filePath - */ - public static boolean deleteFileWithPath(String filePath) { - SecurityManager checker = new SecurityManager(); - File f = new File(filePath); - checker.checkDelete(filePath); - if (f.isFile()) { - Log.i("DirectoryManager deleteFile", filePath); - f.delete(); - return true; - } - return false; - } - - /** - * 清空一个文件夹 - * @param files - */ - public static void clearFileWithPath(String filePath) { - List files = FileUtil.listPathFiles(filePath); - if (files.isEmpty()) { - return; - } - for (File f : files) { - if (f.isDirectory()) { - clearFileWithPath(f.getAbsolutePath()); - } else { - f.delete(); - } - } - } - - /** - * 获取SD卡的根目录 - * - * @return - */ - public static String getSDRoot() { - - return Environment.getExternalStorageDirectory().getAbsolutePath(); - } - - /** - * 获取手机外置SD卡的根目录 - * - * @return - */ - public static String getExternalSDRoot() { - - Map evn = System.getenv(); - - return evn.get("SECONDARY_STORAGE"); - } - - /** - * 列出root目录下所有子目录 - * - * @param path - * @return 绝对路径 - */ - public static List listPath(String root) { - List allDir = new ArrayList(); - SecurityManager checker = new SecurityManager(); - File path = new File(root); - checker.checkRead(root); - // 过滤掉以.开始的文件夹 - if (path.isDirectory()) { - for (File f : path.listFiles()) { - if (f.isDirectory() && !f.getName().startsWith(".")) { - allDir.add(f.getAbsolutePath()); - } - } - } - return allDir; - } - - /** - * 获取一个文件夹下的所有文件 - * @param root - * @return - */ - public static List listPathFiles(String root) { - List allDir = new ArrayList(); - SecurityManager checker = new SecurityManager(); - File path = new File(root); - checker.checkRead(root); - File[] files = path.listFiles(); - for (File f : files) { - if (f.isFile()) - allDir.add(f); - else - listPath(f.getAbsolutePath()); - } - return allDir; - } - - public enum PathStatus { - SUCCESS, EXITS, ERROR - } - - /** - * 创建目录 - * - * @param path - */ - public static PathStatus createPath(String newPath) { - File path = new File(newPath); - if (path.exists()) { - return PathStatus.EXITS; - } - if (path.mkdir()) { - return PathStatus.SUCCESS; - } else { - return PathStatus.ERROR; - } - } - - /** - * 截取路径名 - * - * @return - */ - public static String getPathName(String absolutePath) { - int start = absolutePath.lastIndexOf(File.separator) + 1; - int end = absolutePath.length(); - return absolutePath.substring(start, end); - } - - /** - * 获取应用程序缓存文件夹下的指定目录 - * @param context - * @param dir - * @return - */ - public static String getAppCache(Context context, String dir) { - String savePath = context.getCacheDir().getAbsolutePath() + "/" + dir + "/"; - File savedir = new File(savePath); - if (!savedir.exists()) { - savedir.mkdirs(); - } - savedir = null; - return savePath; - } + * 写文本文件 在Android系统中,文件保存在 /data/data/PACKAGE_NAME/files 目录下 + * + * @param context + * @param msg + */ + public static void write(Context context, String fileName, String content) { + if (content == null) + content = ""; + + try { + FileOutputStream fos = context.openFileOutput(fileName, + Context.MODE_PRIVATE); + fos.write(content.getBytes()); + + fos.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 读取文本文件 + * + * @param context + * @param fileName + * @return + */ + public static String read(Context context, String fileName) { + try { + FileInputStream in = context.openFileInput(fileName); + return readInStream(in); + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + + public static String readInStream(InputStream inStream) { + try { + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + byte[] buffer = new byte[512]; + int length = -1; + while ((length = inStream.read(buffer)) != -1) { + outStream.write(buffer, 0, length); + } + + outStream.close(); + inStream.close(); + return outStream.toString(); + } catch (IOException e) { + Log.i("FileTest", e.getMessage()); + } + return null; + } + + public static File createFile(String folderPath, String fileName) { + File destDir = new File(folderPath); + if (!destDir.exists()) { + destDir.mkdirs(); + } + return new File(folderPath, fileName + fileName); + } + + /** + * 向手机写图片 + * + * @param buffer + * @param folder + * @param fileName + * @return + */ + public static boolean writeFile(byte[] buffer, String folder, + String fileName) { + boolean writeSucc = false; + + boolean sdCardExist = Environment.getExternalStorageState().equals( + android.os.Environment.MEDIA_MOUNTED); + + String folderPath = ""; + if (sdCardExist) { + folderPath = Environment.getExternalStorageDirectory() + + File.separator + folder + File.separator; + } else { + writeSucc = false; + } + + File fileDir = new File(folderPath); + if (!fileDir.exists()) { + fileDir.mkdirs(); + } + + File file = new File(folderPath + fileName); + FileOutputStream out = null; + try { + out = new FileOutputStream(file); + out.write(buffer); + writeSucc = true; + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + return writeSucc; + } + + /** + * 根据文件绝对路径获取文件名 + * + * @param filePath + * @return + */ + public static String getFileName(String filePath) { + if (StringUtils.isEmpty(filePath)) + return ""; + return filePath.substring(filePath.lastIndexOf(File.separator) + 1); + } + + /** + * 根据文件的绝对路径获取文件名但不包含扩展名 + * + * @param filePath + * @return + */ + public static String getFileNameNoFormat(String filePath) { + if (StringUtils.isEmpty(filePath)) { + return ""; + } + int point = filePath.lastIndexOf('.'); + return filePath.substring(filePath.lastIndexOf(File.separator) + 1, + point); + } + + /** + * 获取文件扩展名 + * + * @param fileName + * @return + */ + public static String getFileFormat(String fileName) { + if (StringUtils.isEmpty(fileName)) + return ""; + + int point = fileName.lastIndexOf('.'); + return fileName.substring(point + 1); + } + + /** + * 获取文件大小 + * + * @param filePath + * @return + */ + public static long getFileSize(String filePath) { + long size = 0; + + File file = new File(filePath); + if (file != null && file.exists()) { + size = file.length(); + } + return size; + } + + /** + * 获取文件大小 + * + * @param size 字节 + * @return + */ + public static String getFileSize(long size) { + if (size <= 0) + return "0"; + java.text.DecimalFormat df = new java.text.DecimalFormat("##.##"); + float temp = (float) size / 1024; + if (temp >= 1024) { + return df.format(temp / 1024) + "M"; + } else { + return df.format(temp) + "K"; + } + } + + /** + * 转换文件大小 + * + * @param fileS + * @return B/KB/MB/GB + */ + public static String formatFileSize(long fileS) { + java.text.DecimalFormat df = new java.text.DecimalFormat("#.00"); + String fileSizeString = ""; + if (fileS < 1024) { + fileSizeString = df.format((double) fileS) + "B"; + } else if (fileS < 1048576) { + fileSizeString = df.format((double) fileS / 1024) + "KB"; + } else if (fileS < 1073741824) { + fileSizeString = df.format((double) fileS / 1048576) + "MB"; + } else { + fileSizeString = df.format((double) fileS / 1073741824) + "G"; + } + return fileSizeString; + } + + /** + * 获取目录文件大小 + * + * @param dir + * @return + */ + public static long getDirSize(File dir) { + if (dir == null) { + return 0; + } + if (!dir.isDirectory()) { + return 0; + } + long dirSize = 0; + File[] files = dir.listFiles(); + if (files != null) { + + for (File file : files) { + if (file.isFile()) { + dirSize += file.length(); + } else if (file.isDirectory()) { + dirSize += file.length(); + dirSize += getDirSize(file); // 递归调用继续统计 + } + } + } + return dirSize; + } + + /** + * 获取目录文件个数 + * + * @param emojiFragment + * @return + */ + public long getFileList(File dir) { + long count = 0; + File[] files = dir.listFiles(); + count = files.length; + for (File file : files) { + if (file.isDirectory()) { + count = count + getFileList(file);// 递归 + count--; + } + } + return count; + } + + public static byte[] toBytes(InputStream in) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int ch; + while ((ch = in.read()) != -1) { + out.write(ch); + } + byte buffer[] = out.toByteArray(); + out.close(); + return buffer; + } + + /** + * 检查文件是否存在 + * + * @param name + * @return + */ + public static boolean checkFileExists(String name) { + boolean status; + if (!name.equals("")) { + File path = Environment.getExternalStorageDirectory(); + File newPath = new File(path.toString() + name); + status = newPath.exists(); + } else { + status = false; + } + return status; + } + + /** + * 检查路径是否存在 + * + * @param path + * @return + */ + public static boolean checkFilePathExists(String path) { + return new File(path).exists(); + } + + /** + * 计算SD卡的剩余空间 + * + * @return 返回-1,说明没有安装sd卡 + */ + public static long getFreeDiskSpace() { + String status = Environment.getExternalStorageState(); + long freeSpace = 0; + if (status.equals(Environment.MEDIA_MOUNTED)) { + try { + File path = Environment.getExternalStorageDirectory(); + StatFs stat = new StatFs(path.getPath()); + long blockSize = stat.getBlockSize(); + long availableBlocks = stat.getAvailableBlocks(); + freeSpace = availableBlocks * blockSize / 1024; + } catch (Exception e) { + e.printStackTrace(); + } + } else { + return -1; + } + return (freeSpace); + } + + /** + * 新建目录 + * + * @param directoryName + * @return + */ + public static boolean createDirectory(String directoryName) { + boolean status; + if (!directoryName.equals("")) { + File path = Environment.getExternalStorageDirectory(); + File newPath = new File(path.toString() + directoryName); + status = newPath.mkdir(); + status = true; + } else + status = false; + return status; + } + + /** + * 检查是否安装SD卡 + * + * @return + */ + public static boolean checkSaveLocationExists() { + String sDCardStatus = Environment.getExternalStorageState(); + boolean status; + if (sDCardStatus.equals(Environment.MEDIA_MOUNTED)) { + status = true; + } else + status = false; + return status; + } + + /** + * 检查是否安装外置的SD卡 + * + * @return + */ + public static boolean checkExternalSDExists() { + + Map evn = System.getenv(); + return evn.containsKey("SECONDARY_STORAGE"); + } + + /** + * 删除目录(包括:目录里的所有文件) + * + * @param fileName + * @return + */ + public static boolean deleteDirectory(String fileName) { + boolean status; + SecurityManager checker = new SecurityManager(); + + if (!fileName.equals("")) { + + File path = Environment.getExternalStorageDirectory(); + File newPath = new File(path.toString() + fileName); + checker.checkDelete(newPath.toString()); + if (newPath.isDirectory()) { + String[] listfile = newPath.list(); + try { + for (int i = 0; i < listfile.length; i++) { + File deletedFile = new File(newPath.toString() + "/" + + listfile[i].toString()); + deletedFile.delete(); + } + newPath.delete(); + Log.i("DirectoryManager deleteDirectory", fileName); + status = true; + } catch (Exception e) { + e.printStackTrace(); + status = false; + } + + } else + status = false; + } else + status = false; + return status; + } + + /** + * 删除文件 + * + * @param fileName + * @return + */ + public static boolean deleteFile(String fileName) { + boolean status; + SecurityManager checker = new SecurityManager(); + + if (!fileName.equals("")) { + + File path = Environment.getExternalStorageDirectory(); + File newPath = new File(path.toString() + fileName); + checker.checkDelete(newPath.toString()); + if (newPath.isFile()) { + try { + Log.i("DirectoryManager deleteFile", fileName); + newPath.delete(); + status = true; + } catch (SecurityException se) { + se.printStackTrace(); + status = false; + } + } else + status = false; + } else + status = false; + return status; + } + + /** + * 删除空目录 + *

    + * 返回 0代表成功 ,1 代表没有删除权限, 2代表不是空目录,3 代表未知错误 + * + * @return + */ + public static int deleteBlankPath(String path) { + File f = new File(path); + if (!f.canWrite()) { + return 1; + } + if (f.list() != null && f.list().length > 0) { + return 2; + } + if (f.delete()) { + return 0; + } + return 3; + } + + /** + * 重命名 + * + * @param oldName + * @param newName + * @return + */ + public static boolean reNamePath(String oldName, String newName) { + File f = new File(oldName); + return f.renameTo(new File(newName)); + } + + /** + * 删除文件 + * + * @param filePath + */ + public static boolean deleteFileWithPath(String filePath) { + SecurityManager checker = new SecurityManager(); + File f = new File(filePath); + checker.checkDelete(filePath); + if (f.isFile()) { + Log.i("DirectoryManager deleteFile", filePath); + f.delete(); + return true; + } + return false; + } + + /** + * 清空一个文件夹 + * + * @param files + */ + public static void clearFileWithPath(String filePath) { + List files = FileUtil.listPathFiles(filePath); + if (files.isEmpty()) { + return; + } + for (File f : files) { + if (f.isDirectory()) { + clearFileWithPath(f.getAbsolutePath()); + } else { + f.delete(); + } + } + } + + /** + * 获取SD卡的根目录 + * + * @return + */ + public static String getSDRoot() { + + return Environment.getExternalStorageDirectory().getAbsolutePath(); + } + + /** + * 获取手机外置SD卡的根目录 + * + * @return + */ + public static String getExternalSDRoot() { + + Map evn = System.getenv(); + + return evn.get("SECONDARY_STORAGE"); + } + + /** + * 列出root目录下所有子目录 + * + * @param path + * @return 绝对路径 + */ + public static List listPath(String root) { + List allDir = new ArrayList(); + SecurityManager checker = new SecurityManager(); + File path = new File(root); + checker.checkRead(root); + // 过滤掉以.开始的文件夹 + if (path.isDirectory()) { + for (File f : path.listFiles()) { + if (f.isDirectory() && !f.getName().startsWith(".")) { + allDir.add(f.getAbsolutePath()); + } + } + } + return allDir; + } + + /** + * 获取一个文件夹下的所有文件 + * + * @param root + * @return + */ + public static List listPathFiles(String root) { + List allDir = new ArrayList(); + SecurityManager checker = new SecurityManager(); + File path = new File(root); + checker.checkRead(root); + File[] files = path.listFiles(); + for (File f : files) { + if (f.isFile()) + allDir.add(f); + else + listPath(f.getAbsolutePath()); + } + return allDir; + } + + public enum PathStatus { + SUCCESS, EXITS, ERROR + } + + /** + * 创建目录 + * + * @param path + */ + public static PathStatus createPath(String newPath) { + File path = new File(newPath); + if (path.exists()) { + return PathStatus.EXITS; + } + if (path.mkdir()) { + return PathStatus.SUCCESS; + } else { + return PathStatus.ERROR; + } + } + + /** + * 截取路径名 + * + * @return + */ + public static String getPathName(String absolutePath) { + int start = absolutePath.lastIndexOf(File.separator) + 1; + int end = absolutePath.length(); + return absolutePath.substring(start, end); + } + + /** + * 获取应用程序缓存文件夹下的指定目录 + * + * @param context + * @param dir + * @return + */ + public static String getAppCache(Context context, String dir) { + String savePath = context.getCacheDir().getAbsolutePath() + "/" + dir + "/"; + File savedir = new File(savePath); + if (!savedir.exists()) { + savedir.mkdirs(); + } + savedir = null; + return savePath; + } } \ No newline at end of file diff --git a/app/src/main/java/net/oschina/app/util/HTMLUtil.java b/app/src/main/java/net/oschina/app/util/HTMLUtil.java index 256d6ec324fdae19891a1184347ee31e487435a4..fc92dfdd8b9fb44d6d3ec9a61606f32202d2d440 100644 --- a/app/src/main/java/net/oschina/app/util/HTMLUtil.java +++ b/app/src/main/java/net/oschina/app/util/HTMLUtil.java @@ -1,165 +1,186 @@ package net.oschina.app.util; +import android.text.TextUtils; +import android.widget.Button; + import java.util.regex.Matcher; import java.util.regex.Pattern; public class HTMLUtil { - private static final String regEx_script = "]*?>[\\s\\S]*?<\\/script>"; // 定义script的正则表达式 - private static final String regEx_style = "]*?>[\\s\\S]*?<\\/style>"; // 定义style的正则表达式 - private static final String regEx_html = "<[^>]+>"; // 定义HTML标签的正则表达式 - private final static String regxpForHtml = "<([^>]*)>"; // 过滤所有以<开头以>结尾的标签 + private static final String regEx_script = "]*?>[\\s\\S]*?<\\/script>"; // 定义script的正则表达式 + private static final String regEx_style = "]*?>[\\s\\S]*?<\\/style>"; // 定义style的正则表达式 + private static final String regEx_html = "<[^>]+>"; // 定义HTML标签的正则表达式 + private final static String regxpForHtml = "<([^>]*)>"; // 过滤所有以<开头以>结尾的标签 + + public static String delHTMLTag(String htmlStr) { + Pattern p_script = Pattern.compile(regEx_script, + Pattern.CASE_INSENSITIVE); + Matcher m_script = p_script.matcher(htmlStr); + htmlStr = m_script.replaceAll(""); // 过滤script标签 + + Pattern p_style = Pattern + .compile(regEx_style, Pattern.CASE_INSENSITIVE); + Matcher m_style = p_style.matcher(htmlStr); + htmlStr = m_style.replaceAll(""); // 过滤style标签 - public static String delHTMLTag(String htmlStr) { - Pattern p_script = Pattern.compile(regEx_script, - Pattern.CASE_INSENSITIVE); - Matcher m_script = p_script.matcher(htmlStr); - htmlStr = m_script.replaceAll(""); // 过滤script标签 + Pattern p_html = Pattern.compile(regEx_html, Pattern.CASE_INSENSITIVE); + Matcher m_html = p_html.matcher(htmlStr); + htmlStr = m_html.replaceAll(""); // 过滤html标签 - Pattern p_style = Pattern - .compile(regEx_style, Pattern.CASE_INSENSITIVE); - Matcher m_style = p_style.matcher(htmlStr); - htmlStr = m_style.replaceAll(""); // 过滤style标签 + return htmlStr.trim(); // 返回文本字符串 + } - Pattern p_html = Pattern.compile(regEx_html, Pattern.CASE_INSENSITIVE); - Matcher m_html = p_html.matcher(htmlStr); - htmlStr = m_html.replaceAll(""); // 过滤html标签 + /** + * 基本功能:替换标记以正常显示 + * + * @param input + * @return String + */ + public static String replaceTag(String input) { + if (!hasSpecialChars(input)) { + return input; + } + StringBuffer filtered = new StringBuffer(input.length()); + char c; + for (int i = 0; i <= input.length() - 1; i++) { + c = input.charAt(i); + switch (c) { + case '<': + filtered.append("<"); + break; + case '>': + filtered.append(">"); + break; + case '"': + filtered.append("""); + break; + case '&': + filtered.append("&"); + break; + default: + filtered.append(c); + } - return htmlStr.trim(); // 返回文本字符串 - } - - /** - * 基本功能:替换标记以正常显示 - * @param input - * @return String - */ - public static String replaceTag(String input) { - if (!hasSpecialChars(input)) { - return input; - } - StringBuffer filtered = new StringBuffer(input.length()); - char c; - for (int i = 0; i <= input.length() - 1; i++) { - c = input.charAt(i); - switch (c) { - case '<': - filtered.append("<"); - break; - case '>': - filtered.append(">"); - break; - case '"': - filtered.append("""); - break; - case '&': - filtered.append("&"); - break; - default: - filtered.append(c); - } + } + return (filtered.toString()); + } - } - return (filtered.toString()); - } + /** + * 呵呵 + * @param input + * @return + */ + public static String rollbackReplaceTag(String input){ + if (TextUtils.isEmpty(input)) return input; + return input.replace("<", "<") + .replace(">", ">") + .replace(""", "\"") + .replace("&", "&"); + } - /** - * 基本功能:判断标记是否存在 - * @param input - * @return boolean - */ - public static boolean hasSpecialChars(String input) { - boolean flag = false; - if ((input != null) && (input.length() > 0)) { - char c; - for (int i = 0; i <= input.length() - 1; i++) { - c = input.charAt(i); - switch (c) { - case '>': - flag = true; - break; - case '<': - flag = true; - break; - case '"': - flag = true; - break; - case '&': - flag = true; - break; - } - } - } - return flag; - } + /** + * 基本功能:判断标记是否存在 + * + * @param input + * @return boolean + */ + public static boolean hasSpecialChars(String input) { + boolean flag = false; + if ((input != null) && (input.length() > 0)) { + char c; + for (int i = 0; i <= input.length() - 1; i++) { + c = input.charAt(i); + switch (c) { + case '>': + flag = true; + break; + case '<': + flag = true; + break; + case '"': + flag = true; + break; + case '&': + flag = true; + break; + } + } + } + return flag; + } - /** - * 基本功能:过滤所有以"<"开头以">"结尾的标签 - * @param str - * @return String - */ - public static String filterHtml(String str) { - Pattern pattern = Pattern.compile(regxpForHtml); - Matcher matcher = pattern.matcher(str); - StringBuffer sb = new StringBuffer(); - boolean result1 = matcher.find(); - while (result1) { - matcher.appendReplacement(sb, ""); - result1 = matcher.find(); - } - matcher.appendTail(sb); - return sb.toString(); - } + /** + * 基本功能:过滤所有以"<"开头以">"结尾的标签 + * + * @param str + * @return String + */ + public static String filterHtml(String str) { + Pattern pattern = Pattern.compile(regxpForHtml); + Matcher matcher = pattern.matcher(str); + StringBuffer sb = new StringBuffer(); + boolean result1 = matcher.find(); + while (result1) { + matcher.appendReplacement(sb, ""); + result1 = matcher.find(); + } + matcher.appendTail(sb); + return sb.toString(); + } - /** - * 基本功能:过滤指定标签 - * @param str - * @param tag 指定标签 - * @return String - */ - public static String fiterHtmlTag(String str, String tag) { - String regxp = "<\\s*" + tag + "\\s+([^>]*)\\s*>"; - Pattern pattern = Pattern.compile(regxp); - Matcher matcher = pattern.matcher(str); - StringBuffer sb = new StringBuffer(); - boolean result1 = matcher.find(); - while (result1) { - matcher.appendReplacement(sb, ""); - result1 = matcher.find(); - } - matcher.appendTail(sb); - return sb.toString(); - } + /** + * 基本功能:过滤指定标签 + * + * @param str + * @param tag 指定标签 + * @return String + */ + public static String fiterHtmlTag(String str, String tag) { + String regxp = "<\\s*" + tag + "\\s+([^>]*)\\s*>"; + Pattern pattern = Pattern.compile(regxp); + Matcher matcher = pattern.matcher(str); + StringBuffer sb = new StringBuffer(); + boolean result1 = matcher.find(); + while (result1) { + matcher.appendReplacement(sb, ""); + result1 = matcher.find(); + } + matcher.appendTail(sb); + return sb.toString(); + } - /** - * 基本功能:替换指定的标签 - * @param str - * @param beforeTag 要替换的标签 - * @param tagAttrib 要替换的标签属性值 - * @param startTag 新标签开始标记 - * @param endTag 新标签结束标记 - * @return String - * @如:替换img标签的src属性值为[img]属性值[/img] - */ - public static String replaceHtmlTag(String str, String beforeTag, - String tagAttrib, String startTag, String endTag) { - String regxpForTag = "<\\s*" + beforeTag + "\\s+([^>]*)\\s*>"; - String regxpForTagAttrib = tagAttrib + "=\"([^\"]+)\""; - Pattern patternForTag = Pattern.compile(regxpForTag); - Pattern patternForAttrib = Pattern.compile(regxpForTagAttrib); - Matcher matcherForTag = patternForTag.matcher(str); - StringBuffer sb = new StringBuffer(); - boolean result = matcherForTag.find(); - while (result) { - StringBuffer sbreplace = new StringBuffer(); - Matcher matcherForAttrib = patternForAttrib.matcher(matcherForTag - .group(1)); - if (matcherForAttrib.find()) { - matcherForAttrib.appendReplacement(sbreplace, startTag - + matcherForAttrib.group(1) + endTag); - } - matcherForTag.appendReplacement(sb, sbreplace.toString()); - result = matcherForTag.find(); - } - matcherForTag.appendTail(sb); - return sb.toString(); - } + /** + * 基本功能:替换指定的标签 + * + * @param str + * @param beforeTag 要替换的标签 + * @param tagAttrib 要替换的标签属性值 + * @param startTag 新标签开始标记 + * @param endTag 新标签结束标记 + * @return String + * @如:替换img标签的src属性值为[img]属性值[/img] + */ + public static String replaceHtmlTag(String str, String beforeTag, + String tagAttrib, String startTag, String endTag) { + String regxpForTag = "<\\s*" + beforeTag + "\\s+([^>]*)\\s*>"; + String regxpForTagAttrib = tagAttrib + "=\"([^\"]+)\""; + Pattern patternForTag = Pattern.compile(regxpForTag); + Pattern patternForAttrib = Pattern.compile(regxpForTagAttrib); + Matcher matcherForTag = patternForTag.matcher(str); + StringBuffer sb = new StringBuffer(); + boolean result = matcherForTag.find(); + while (result) { + StringBuffer sbreplace = new StringBuffer(); + Matcher matcherForAttrib = patternForAttrib.matcher(matcherForTag + .group(1)); + if (matcherForAttrib.find()) { + matcherForAttrib.appendReplacement(sbreplace, startTag + + matcherForAttrib.group(1) + endTag); + } + matcherForTag.appendReplacement(sb, sbreplace.toString()); + result = matcherForTag.find(); + } + matcherForTag.appendTail(sb); + return sb.toString(); + } } diff --git a/app/src/main/java/net/oschina/app/util/ImageLoader.java b/app/src/main/java/net/oschina/app/util/ImageLoader.java new file mode 100644 index 0000000000000000000000000000000000000000..a2c55d0b06d98ac825be3d6686ababd4af6ad9ab --- /dev/null +++ b/app/src/main/java/net/oschina/app/util/ImageLoader.java @@ -0,0 +1,71 @@ +package net.oschina.app.util; + +import android.graphics.Bitmap; +import android.support.v4.graphics.drawable.RoundedBitmapDrawable; +import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory; +import android.text.TextUtils; +import android.widget.ImageView; + +import com.bumptech.glide.BitmapRequestBuilder; +import com.bumptech.glide.DrawableRequestBuilder; +import com.bumptech.glide.RequestManager; +import com.bumptech.glide.load.engine.DiskCacheStrategy; +import com.bumptech.glide.request.target.BitmapImageViewTarget; + +import de.hdodenhof.circleimageview.CircleImageView; + +/** + * Glide 图片加载辅助类 + * 适配圆形图片加载情况 + */ + +public class ImageLoader { + private ImageLoader() { + } + + public static void loadImage(RequestManager loader, ImageView view, String url) { + loadImage(loader, view, url, 0); + } + + public static void loadImage(RequestManager loader, ImageView view, String url, int placeholder) { + loadImage(loader, view, url, placeholder, placeholder); + } + + public static void loadImage(RequestManager loader, ImageView view, String url, int placeholder, int error) { + boolean isCenterCrop = false; + if (view instanceof CircleImageView) + isCenterCrop = true; + loadImage(loader, view, url, placeholder, error, isCenterCrop); + } + + public static void loadImage(RequestManager loader, ImageView view, String url, int placeholder, int error, boolean isCenterCrop) { + if (TextUtils.isEmpty(url)) { + view.setImageResource(placeholder); + } else { + if (view instanceof CircleImageView) { + BitmapRequestBuilder builder = loader.load(url).asBitmap() + .diskCacheStrategy(DiskCacheStrategy.ALL) + .placeholder(placeholder) + .error(error); + if (isCenterCrop) + builder.centerCrop(); + + builder.into( + new BitmapImageViewTarget(view) { + @Override + protected void setResource(Bitmap resource) { + RoundedBitmapDrawable circularBitmapDrawable = + RoundedBitmapDrawableFactory.create(view.getResources(), resource); + circularBitmapDrawable.setCircular(true); + view.setImageDrawable(circularBitmapDrawable); + } + }); + } else { + DrawableRequestBuilder builder = loader.load(url).diskCacheStrategy(DiskCacheStrategy.ALL).placeholder(placeholder).error(error); + if (isCenterCrop) + builder.centerCrop(); + builder.into(view); + } + } + } +} diff --git a/app/src/main/java/net/oschina/app/util/ImageUtils.java b/app/src/main/java/net/oschina/app/util/ImageUtils.java index 2df194f6b7afea5f94746d3a1db6ef4bb9fe2782..ab86f9fe5cd03a3f0fb717fc4efb55c310154086 100644 --- a/app/src/main/java/net/oschina/app/util/ImageUtils.java +++ b/app/src/main/java/net/oschina/app/util/ImageUtils.java @@ -1,18 +1,9 @@ package net.oschina.app.util; -import java.io.BufferedOutputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.sql.Timestamp; -import java.text.SimpleDateFormat; - +import android.annotation.SuppressLint; import android.app.Activity; import android.content.ContentResolver; +import android.content.ContentUris; import android.content.Context; import android.content.Intent; import android.database.Cursor; @@ -33,14 +24,27 @@ import android.graphics.Shader.TileMode; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; +import android.os.Build; import android.os.Environment; +import android.provider.DocumentsContract; import android.provider.MediaStore; import android.provider.MediaStore.MediaColumns; import android.util.DisplayMetrics; +import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.sql.Timestamp; +import java.text.SimpleDateFormat; + /** * 图片操作工具包 - * + * * @author liux (http://my.oschina.net/liux) * @version 1.0 * @created 2012-3-21 @@ -50,18 +54,26 @@ public class ImageUtils { public final static String SDCARD_MNT = "/mnt/sdcard"; public final static String SDCARD = "/sdcard"; - /** 请求相册 */ + /** + * 请求相册 + */ public static final int REQUEST_CODE_GETIMAGE_BYSDCARD = 0; - /** 请求相机 */ + /** + * 请求相机 + */ public static final int REQUEST_CODE_GETIMAGE_BYCAMERA = 1; - /** 请求裁剪 */ + /** + * 请求裁剪 + */ public static final int REQUEST_CODE_GETIMAGE_BYCROP = 2; - /** 从图片浏览界面发送动弹 */ + /** + * 从图片浏览界面发送动弹 + */ public static final int REQUEST_CODE_GETIMAGE_IMAGEPAVER = 3; /** * 写图片文件 在Android系统中,文件保存在 /data/data/PACKAGE_NAME/files 目录下 - * + * * @throws IOException */ public static void saveImage(Context context, String fileName, Bitmap bitmap) @@ -70,7 +82,7 @@ public class ImageUtils { } public static void saveImage(Context context, String fileName, - Bitmap bitmap, int quality) throws IOException { + Bitmap bitmap, int quality) throws IOException { if (bitmap == null || fileName == null || context == null) return; @@ -85,11 +97,11 @@ public class ImageUtils { /** * 写图片文件到SD卡 - * + * * @throws IOException */ public static void saveImageToSD(Context ctx, String filePath, - Bitmap bitmap, int quality) throws IOException { + Bitmap bitmap, int quality) throws IOException { if (bitmap != null) { File file = new File(filePath.substring(0, filePath.lastIndexOf(File.separator))); @@ -108,7 +120,7 @@ public class ImageUtils { } public static void saveBackgroundImage(Context ctx, String filePath, - Bitmap bitmap, int quality) throws IOException { + Bitmap bitmap, int quality) throws IOException { if (bitmap != null) { File file = new File(filePath.substring(0, filePath.lastIndexOf(File.separator))); @@ -140,7 +152,7 @@ public class ImageUtils { /** * 获取bitmap - * + * * @param context * @param fileName * @return @@ -166,7 +178,7 @@ public class ImageUtils { /** * 获取bitmap - * + * * @param filePath * @return */ @@ -175,7 +187,7 @@ public class ImageUtils { } public static Bitmap getBitmapByPath(String filePath, - BitmapFactory.Options opts) { + BitmapFactory.Options opts) { FileInputStream fis = null; Bitmap bitmap = null; try { @@ -197,7 +209,7 @@ public class ImageUtils { /** * 获取bitmap - * + * * @param file * @return */ @@ -222,7 +234,7 @@ public class ImageUtils { /** * 使用当前时间戳拼接一个唯一的文件名 - * + * * @param format * @return */ @@ -235,7 +247,7 @@ public class ImageUtils { /** * 获取照相机使用的目录 - * + * * @return */ public static String getCamerPath() { @@ -245,7 +257,7 @@ public class ImageUtils { /** * 判断当前Url是否标准的content://样式,如果不是,则返回绝对路径 - * + * * @param uri * @return */ @@ -270,16 +282,16 @@ public class ImageUtils { /** * 通过uri获取文件的绝对路径 - * + * * @param uri * @return */ @SuppressWarnings("deprecation") public static String getAbsoluteImagePath(Activity context, Uri uri) { String imagePath = ""; - String[] proj = { MediaStore.Images.Media.DATA }; + String[] proj = {MediaStore.Images.Media.DATA}; Cursor cursor = context.managedQuery(uri, proj, // Which columns to - // return + // return null, // WHERE clause; which rows to return (all rows) null, // WHERE clause selection arguments (none) null); // Order-by clause (ascending by name) @@ -297,19 +309,18 @@ public class ImageUtils { /** * 获取图片缩略图 只有Android2.1以上版本支持 - * + * * @param imgName - * @param kind - * MediaStore.Images.Thumbnails.MICRO_KIND + * @param kind MediaStore.Images.Thumbnails.MICRO_KIND * @return */ @SuppressWarnings("deprecation") public static Bitmap loadImgThumbnail(Activity context, String imgName, - int kind) { + int kind) { Bitmap bitmap = null; - String[] proj = { MediaStore.Images.Media._ID, - MediaStore.Images.Media.DISPLAY_NAME }; + String[] proj = {MediaStore.Images.Media._ID, + MediaStore.Images.Media.DISPLAY_NAME}; Cursor cursor = context.managedQuery( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, proj, @@ -333,13 +344,13 @@ public class ImageUtils { /** * 获取SD卡中最新图片路径 - * + * * @return */ public static String getLatestImage(Activity context) { String latestImage = null; - String[] items = { MediaStore.Images.Media._ID, - MediaStore.Images.Media.DATA }; + String[] items = {MediaStore.Images.Media._ID, + MediaStore.Images.Media.DATA}; Cursor cursor = context.managedQuery( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, items, null, null, MediaStore.Images.Media._ID + " desc"); @@ -358,7 +369,7 @@ public class ImageUtils { /** * 计算缩放图片的宽高 - * + * * @param img_size * @param square_size * @return @@ -368,27 +379,23 @@ public class ImageUtils { return img_size; double ratio = square_size / (double) Math.max(img_size[0], img_size[1]); - return new int[] { (int) (img_size[0] * ratio), - (int) (img_size[1] * ratio) }; + return new int[]{(int) (img_size[0] * ratio), + (int) (img_size[1] * ratio)}; } /** * 创建缩略图 - * + * * @param context - * @param largeImagePath - * 原始大图路径 - * @param thumbfilePath - * 输出缩略图路径 - * @param square_size - * 输出图片宽度 - * @param quality - * 输出图片质量 + * @param largeImagePath 原始大图路径 + * @param thumbfilePath 输出缩略图路径 + * @param square_size 输出图片宽度 + * @param quality 输出图片质量 * @throws IOException */ public static void createImageThumbnail(Context context, - String largeImagePath, String thumbfilePath, int square_size, - int quality) throws IOException { + String largeImagePath, String thumbfilePath, int square_size, + int quality) throws IOException { BitmapFactory.Options opts = new BitmapFactory.Options(); opts.inSampleSize = 1; // 原始图片bitmap @@ -398,8 +405,8 @@ public class ImageUtils { return; // 原始图片的高宽 - int[] cur_img_size = new int[] { cur_bitmap.getWidth(), - cur_bitmap.getHeight() }; + int[] cur_img_size = new int[]{cur_bitmap.getWidth(), + cur_bitmap.getHeight()}; // 计算原始图片缩放后的宽高 int[] new_img_size = scaleImageSize(cur_img_size, square_size); // 生成缩放后的bitmap @@ -411,7 +418,7 @@ public class ImageUtils { /** * 放大缩小图片 - * + * * @param bitmap * @param w * @param h @@ -456,9 +463,8 @@ public class ImageUtils { /** * (缩放)重绘图片 - * - * @param context - * Activity + * + * @param context Activity * @param bitmap * @return */ @@ -491,7 +497,7 @@ public class ImageUtils { /** * 将Drawable转化为Bitmap - * + * * @param drawable * @return */ @@ -510,10 +516,9 @@ public class ImageUtils { /** * 获得圆角图片的方法 - * + * * @param bitmap - * @param roundPx - * 一般设成14 + * @param roundPx 一般设成14 * @return */ public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, float roundPx) { @@ -540,7 +545,7 @@ public class ImageUtils { /** * 获得带倒影的图片方法 - * + * * @param bitmap * @return */ @@ -581,7 +586,7 @@ public class ImageUtils { /** * 将bitmap转化为drawable - * + * * @param bitmap * @return */ @@ -592,7 +597,7 @@ public class ImageUtils { /** * 获取图片类型 - * + * * @param file * @return */ @@ -619,7 +624,7 @@ public class ImageUtils { /** * 获取图片的类型信息 - * + * * @param in * @return * @see #getImageType(byte[]) @@ -639,9 +644,8 @@ public class ImageUtils { /** * 获取图片的类型信息 - * - * @param bytes - * 2~8 byte at beginning of the image file + * + * @param bytes 2~8 byte at beginning of the image file * @return image mimetype or null if the file is not image */ public static String getImageType(byte[] bytes) { @@ -692,41 +696,86 @@ public class ImageUtils { } /** - * 获取图片路径 2014年8月12日 - * - * @param uri - * @param cursor - * @return E-mail:mr.huangwenwei@gmail.com + * 通过Uri获取文件路径 + * 支持图片媒体,文件等 + *

    + * Author qiujuer@live.cn + * + * @param uri Uri + * @param context Context + * @return 文件路径 */ - public static String getImagePath(Uri uri, Activity context) { - - String[] projection = { MediaColumns.DATA }; - Cursor cursor = context.getContentResolver().query(uri, projection, - null, null, null); - if (cursor != null) { - cursor.moveToFirst(); - int columIndex = cursor.getColumnIndexOrThrow(MediaColumns.DATA); - String ImagePath = cursor.getString(columIndex); - cursor.close(); - return ImagePath; + @SuppressLint({"NewApi", "Recycle"}) + public static String getImagePath(Uri uri, Context context) { + String selection = null; + String[] selectionArgs = null; + // Uri is different in versions after KITKAT (Android 4.4), we need to + if (Build.VERSION.SDK_INT >= 19 && DocumentsContract.isDocumentUri(context.getApplicationContext(), uri)) { + String authority = uri.getAuthority(); + if ("com.android.externalstorage.documents".equals(authority)) { + // isExternalStorageDocument + final String docId = DocumentsContract.getDocumentId(uri); + final String[] split = docId.split(":"); + return Environment.getExternalStorageDirectory() + "/" + split[1]; + } else if ("com.android.providers.downloads.documents".equals(authority)) { + // isDownloadsDocument + final String id = DocumentsContract.getDocumentId(uri); + uri = ContentUris.withAppendedId( + Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); + } else if ("com.android.providers.media.documents".equals(authority)) { + // isMediaDocument + final String docId = DocumentsContract.getDocumentId(uri); + final String[] split = docId.split(":"); + final String type = split[0]; + if ("image".equals(type)) { + uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; + } else if ("video".equals(type)) { + uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; + } else if ("audio".equals(type)) { + uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; + } + selection = "_id=?"; + selectionArgs = new String[]{ + split[1] + }; + } } - - return uri.toString(); + if ("content".equalsIgnoreCase(uri.getScheme())) { + String[] projection = {MediaStore.Images.Media.DATA}; + Cursor cursor = null; + try { + cursor = context.getContentResolver() + .query(uri, projection, selection, selectionArgs, null); + if (cursor != null) { + int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); + if (cursor.moveToFirst()) { + return cursor.getString(column_index); + } + } + } catch (Exception e) { + e.fillInStackTrace(); + } finally { + if (cursor != null) + cursor.close(); + } + } else if ("file".equalsIgnoreCase(uri.getScheme())) { + return uri.getPath(); + } + return null; } static Bitmap bitmap = null; /** * 2014年8月13日 - * + * * @param uri - * @param context - * E-mail:mr.huangwenwei@gmail.com + * @param context E-mail:mr.huangwenwei@gmail.com */ public static Bitmap loadPicasaImageFromGalley(final Uri uri, - final Activity context) { + final Activity context) { - String[] projection = { MediaColumns.DATA, MediaColumns.DISPLAY_NAME }; + String[] projection = {MediaColumns.DATA, MediaColumns.DISPLAY_NAME}; Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null); if (cursor != null) { diff --git a/app/src/main/java/net/oschina/app/util/PlatfromUtil.java b/app/src/main/java/net/oschina/app/util/PlatfromUtil.java index 365525318a58de8876efe9cd8533b23142760562..e2872898ac598d72817f641474704711536b3087 100644 --- a/app/src/main/java/net/oschina/app/util/PlatfromUtil.java +++ b/app/src/main/java/net/oschina/app/util/PlatfromUtil.java @@ -39,6 +39,7 @@ public class PlatfromUtil { tv.setVisibility(View.GONE); } String platFromStr = AppContext.getInstance().getResources().getString(resId); - TypefaceUtils.setTypeFaceWithText(tv, R.string.fa_mobile, platFromStr); + tv.setText(platFromStr); +// TypefaceUtils.setTypeFaceWithText(tv, R.string.fa_mobile, platFromStr); } } diff --git a/app/src/main/java/net/oschina/app/util/SimpleTextWatcher.java b/app/src/main/java/net/oschina/app/util/SimpleTextWatcher.java index 4a1849ff00f56ab2d88c29df844525a5c6e17a94..feda08b3e5cd92047c901470e2a400bb763a4313 100644 --- a/app/src/main/java/net/oschina/app/util/SimpleTextWatcher.java +++ b/app/src/main/java/net/oschina/app/util/SimpleTextWatcher.java @@ -8,20 +8,14 @@ public class SimpleTextWatcher implements TextWatcher { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { - // TODO Auto-generated method stub - } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { - // TODO Auto-generated method stub - } @Override public void afterTextChanged(Editable s) { - // TODO Auto-generated method stub - } } diff --git a/app/src/main/java/net/oschina/app/util/StringUtils.java b/app/src/main/java/net/oschina/app/util/StringUtils.java index 1876c18511bc303a062d792989ad0f65f7fe3e9b..97f3697d960cc1a628dce43cd7beab2ab95d85ee 100644 --- a/app/src/main/java/net/oschina/app/util/StringUtils.java +++ b/app/src/main/java/net/oschina/app/util/StringUtils.java @@ -1,24 +1,30 @@ package net.oschina.app.util; +import android.app.AlarmManager; +import android.text.TextUtils; +import android.util.Log; + import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; -import java.util.TimeZone; +import java.util.Locale; +import java.util.regex.Matcher; import java.util.regex.Pattern; /** * 字符串操作工具包 - * + * * @author liux (http://my.oschina.net/liux) - * @version 1.0 - * @created 2012-3-21 + * @author thanatosx + * @version 2.0 + * Updated 2016-08-11 */ public class StringUtils { + private final static Pattern emailer = Pattern .compile("\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*"); @@ -28,318 +34,347 @@ public class StringUtils { private final static Pattern URL = Pattern .compile("^(https|http)://.*?$(net|com|.com.cn|org|me|)"); - private final static ThreadLocal dateFormater = new ThreadLocal() { + private final static ThreadLocal YYYYMMDDHHMMSS = new ThreadLocal() { + @Override + protected SimpleDateFormat initialValue() { + return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()); + } + }; + + private final static ThreadLocal YYYYMMDD = new ThreadLocal() { @Override protected SimpleDateFormat initialValue() { - return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + return new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); } }; - private final static ThreadLocal dateFormater2 = new ThreadLocal() { + private final static ThreadLocal YYYYMMDDHHMM = new ThreadLocal() { @Override protected SimpleDateFormat initialValue() { - return new SimpleDateFormat("yyyy-MM-dd"); + return new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault()); } }; + private static final Pattern UniversalDatePattern = Pattern.compile( + "([0-9]{4})-([0-9]{2})-([0-9]{2})[\\s]+([0-9]{2}):([0-9]{2}):([0-9]{2})" + ); + /** * 将字符串转位日期类型 - * - * @param sdate - * @return + * + * @param sdate string date that's type like YYYY-MM-DD HH:mm:ss + * @return {@link Date} */ public static Date toDate(String sdate) { - return toDate(sdate, dateFormater.get()); + return toDate(sdate, YYYYMMDDHHMMSS.get()); } - public static Date toDate(String sdate, SimpleDateFormat dateFormater) { + public static Date toDate(String sdate, SimpleDateFormat formatter) { try { - return dateFormater.parse(sdate); - } catch (ParseException e) { + return formatter.parse(sdate); + } catch (Exception e) { return null; } } + /** + * YYYY-MM-DD HH:mm:ss格式的时间字符串转换为{@link Calendar}类型 + * + * @param str YYYY-MM-DD HH:mm:ss格式字符串 + * @return {@link Calendar} + */ + public static Calendar parseCalendar(String str) { + Matcher matcher = UniversalDatePattern.matcher(str); + Calendar calendar = Calendar.getInstance(); + if (!matcher.find()) return null; + calendar.set( + matcher.group(1) == null ? 0 : toInt(matcher.group(1)), + matcher.group(2) == null ? 0 : toInt(matcher.group(2)) - 1, + matcher.group(3) == null ? 0 : toInt(matcher.group(3)), + matcher.group(4) == null ? 0 : toInt(matcher.group(4)), + matcher.group(5) == null ? 0 : toInt(matcher.group(5)), + matcher.group(6) == null ? 0 : toInt(matcher.group(6)) + ); + return calendar; + } + + /** + * transform date to string that's type like YYYY-MM-DD HH:mm:ss + * + * @param date {@link Date} + * @return + */ public static String getDateString(Date date) { - return dateFormater.get().format(date); + return YYYYMMDDHHMMSS.get().format(date); } /** - * 以友好的方式显示时间 - * + * transform date to string that's type like YYYY-MM-DD HH:mm + * * @param sdate * @return */ - public static String friendly_time(String sdate) { - Date time = null; - - if (TimeZoneUtil.isInEasternEightZones()) - time = toDate(sdate); - else - time = TimeZoneUtil.transformTime(toDate(sdate), - TimeZone.getTimeZone("GMT+08"), TimeZone.getDefault()); - - if (time == null) { - return "Unknown"; - } - String ftime = ""; - Calendar cal = Calendar.getInstance(); - - // 判断是否是同一天 - String curDate = dateFormater2.get().format(cal.getTime()); - String paramDate = dateFormater2.get().format(time); - if (curDate.equals(paramDate)) { - int hour = (int) ((cal.getTimeInMillis() - time.getTime()) / 3600000); - if (hour == 0) - ftime = Math.max( - (cal.getTimeInMillis() - time.getTime()) / 60000, 1) - + "分钟前"; - else - ftime = hour + "小时前"; - return ftime; - } - - long lt = time.getTime() / 86400000; - long ct = cal.getTimeInMillis() / 86400000; - int days = (int) (ct - lt); - if (days == 0) { - int hour = (int) ((cal.getTimeInMillis() - time.getTime()) / 3600000); - if (hour == 0) - ftime = Math.max( - (cal.getTimeInMillis() - time.getTime()) / 60000, 1) - + "分钟前"; - else - ftime = hour + "小时前"; - } else if (days == 1) { - ftime = "昨天"; - } else if (days == 2) { - ftime = "前天 "; - } else if (days > 2 && days < 31) { - ftime = days + "天前"; - } else if (days >= 31 && days <= 2 * 31) { - ftime = "一个月前"; - } else if (days > 2 * 31 && days <= 3 * 31) { - ftime = "2个月前"; - } else if (days > 3 * 31 && days <= 4 * 31) { - ftime = "3个月前"; - } else { - ftime = dateFormater2.get().format(time); - } - return ftime; + public static String getDateString(String sdate) { + if (TextUtils.isEmpty(sdate)) return ""; + return YYYYMMDDHHMM.get().format(toDate(sdate)); } - public static String friendly_time2(String sdate) { - String res = ""; - if (isEmpty(sdate)) - return ""; - String[] weekDays = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" }; - String currentData = StringUtils.getDataTime("MM-dd"); - int currentDay = toInt(currentData.substring(3)); - int currentMoth = toInt(currentData.substring(0, 2)); + public static String formatYearMonthDay(String st) { + if (TextUtils.isEmpty(st)) return ""; + Matcher matcher = UniversalDatePattern.matcher(st); + if (!matcher.find()) return st; + return String.format("%s年%s月%s日", + matcher.group(1) == null ? 0 : matcher.group(1), + matcher.group(2) == null ? 0 : matcher.group(2), + matcher.group(3) == null ? 0 : matcher.group(3)); + } - int sMoth = toInt(sdate.substring(5, 7)); - int sDay = toInt(sdate.substring(8, 10)); - int sYear = toInt(sdate.substring(0, 4)); - Date dt = new Date(sYear, sMoth - 1, sDay - 1); + public static String formatYearMonthDayNew(String st) { + if (TextUtils.isEmpty(st)) return ""; + Matcher matcher = UniversalDatePattern.matcher(st); + if (!matcher.find()) return st; + return String.format("%s/%s/%s", + matcher.group(1) == null ? 0 : matcher.group(1), + matcher.group(2) == null ? 0 : matcher.group(2), + matcher.group(3) == null ? 0 : matcher.group(3)); + } - if (sDay == currentDay && sMoth == currentMoth) { - res = "今天 / " + weekDays[getWeekOfDate(new Date())]; - } else if (sDay == currentDay + 1 && sMoth == currentMoth) { - res = "昨天 / " + weekDays[(getWeekOfDate(new Date()) + 6) % 7]; - } else { - if (sMoth < 10) { - res = "0"; - } - res += sMoth + "/"; - if (sDay < 10) { - res += "0"; - } - res += sDay + " / " + weekDays[getWeekOfDate(dt)]; + /** + * format time friendly + * + * @param sdate YYYY-MM-DD HH:mm:ss + * @return n分钟前, n小时前, 昨天, 前天, n天前, n个月前 + */ + public static String formatSomeAgo(String sdate) { + if (sdate == null) return ""; + Calendar calendar = parseCalendar(sdate); + if (calendar == null) return sdate; + + Calendar mCurrentDate = Calendar.getInstance(); + long crim = mCurrentDate.getTimeInMillis(); // current + long trim = calendar.getTimeInMillis(); // target + long diff = crim - trim; + + int year = mCurrentDate.get(Calendar.YEAR); + int month = mCurrentDate.get(Calendar.MONTH); + int day = mCurrentDate.get(Calendar.DATE); + + if (diff < 60 * 1000) { + return "刚刚"; } - - return res; + if (diff >= 60 * 1000 && diff < AlarmManager.INTERVAL_HOUR) { + return String.format("%s分钟前", diff / 60 / 1000); + } + mCurrentDate.set(year, month, day, 0, 0, 0); + if (trim >= mCurrentDate.getTimeInMillis()) { + return String.format("%s小时前", diff / AlarmManager.INTERVAL_HOUR); + } + mCurrentDate.set(year, month, day - 1, 0, 0, 0); + if (trim >= mCurrentDate.getTimeInMillis()) { + return "昨天"; + } + mCurrentDate.set(year, month, day - 2, 0, 0, 0); + if (trim >= mCurrentDate.getTimeInMillis()) { + return "前天"; + } + if (diff < AlarmManager.INTERVAL_DAY * 30) { + return String.format("%s天前", diff / AlarmManager.INTERVAL_DAY); + } + if (diff < AlarmManager.INTERVAL_DAY * 30 * 12) { + return String.format("%s月前", diff / (AlarmManager.INTERVAL_DAY * 30)); + } + return String.format("%s年前", mCurrentDate.get(Calendar.YEAR) - calendar.get(Calendar.YEAR)); } - /** - * 智能格式化 + * @param str YYYY-MM-DD HH:mm:ss string + * @return 今天, 昨天, 前天, n天前 */ - public static String friendly_time3(String sdate) { - String res = ""; - if (isEmpty(sdate)) - return ""; + public static String formatSomeDay(String str) { + return formatSomeDay(parseCalendar(str)); + } - Date date = StringUtils.toDate(sdate); - if (date == null) - return sdate; - - SimpleDateFormat format = dateFormater2.get(); - - if (isToday(date.getTime())) { - format.applyPattern(isMorning(date.getTime()) ? "上午 hh:mm" : "下午 hh:mm"); - res = format.format(date); - } else if (isYesterday(date.getTime())) { - format.applyPattern(isMorning(date.getTime()) ? "昨天 上午 hh:mm" : "昨天 下午 hh:mm"); - res = format.format(date); - } else if (isCurrentYear(date.getTime())) { - format.applyPattern(isMorning(date.getTime()) ? "MM-dd 上午 hh:mm" : "MM-dd 下午 hh:mm"); - res = format.format(date); - } else { - format.applyPattern(isMorning(date.getTime()) ? "yyyy-MM-dd 上午 hh:mm" : "yyyy-MM-dd 下午 hh:mm"); - res = format.format(date); + /** + * @param calendar {@link Calendar} + * @return 今天, 昨天, 前天, n天前 + */ + public static String formatSomeDay(Calendar calendar) { + if (calendar == null) return "?天前"; + Calendar mCurrentDate = Calendar.getInstance(); + long crim = mCurrentDate.getTimeInMillis(); // current + long trim = calendar.getTimeInMillis(); // target + long diff = crim - trim; + + int year = mCurrentDate.get(Calendar.YEAR); + int month = mCurrentDate.get(Calendar.MONTH); + int day = mCurrentDate.get(Calendar.DATE); + + mCurrentDate.set(year, month, day, 0, 0, 0); + if (trim >= mCurrentDate.getTimeInMillis()) { + return "今天"; + } + mCurrentDate.set(year, month, day - 1, 0, 0, 0); + if (trim >= mCurrentDate.getTimeInMillis()) { + return "昨天"; } - return res; + mCurrentDate.set(year, month, day - 2, 0, 0, 0); + if (trim >= mCurrentDate.getTimeInMillis()) { + return "前天"; + } + return String.format("%s天前", diff / AlarmManager.INTERVAL_DAY); } /** - * @return 判断一个时间是不是上午 + * @param calendar {@link Calendar} + * @return 星期n */ - public static boolean isMorning(long when) { - android.text.format.Time time = new android.text.format.Time(); - time.set(when); - - int hour = time.hour; - return (hour >= 0) && (hour < 12); + public static String formatWeek(Calendar calendar) { + if (calendar == null) return "星期?"; + return new String[]{"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"}[calendar.get(Calendar.DAY_OF_WEEK) - 1]; } /** - * @return 判断一个时间是不是今天 + * @param str YYYY-MM-DD HH:mm:ss string + * @return 星期n */ - public static boolean isToday(long when) { - android.text.format.Time time = new android.text.format.Time(); - time.set(when); - - int thenYear = time.year; - int thenMonth = time.month; - int thenMonthDay = time.monthDay; - - time.set(System.currentTimeMillis()); - return (thenYear == time.year) - && (thenMonth == time.month) - && (thenMonthDay == time.monthDay); + public static String formatWeek(String str) { + return formatWeek(parseCalendar(str)); } /** - * @return 判断一个时间是不是昨天 + * @param sdate YYYY-MM-DD HH:mm:ss string + * @return */ - public static boolean isYesterday(long when) { - android.text.format.Time time = new android.text.format.Time(); - time.set(when); - - int thenYear = time.year; - int thenMonth = time.month; - int thenMonthDay = time.monthDay; - - time.set(System.currentTimeMillis()); - return (thenYear == time.year) - && (thenMonth == time.month) - && (time.monthDay - thenMonthDay == 1); + public static String formatDayWeek(String sdate) { + Calendar calendar = parseCalendar(sdate); + if (calendar == null) return "??/?? 星期?"; + Calendar mCurrentDate = Calendar.getInstance(); + String ws = formatWeek(calendar); + int diff = mCurrentDate.get(Calendar.DATE) - calendar.get(Calendar.DATE); + if (diff == 0) { + return "今天 / " + ws; + } + if (diff == 1) { + return "昨天 / " + ws; + } + int m = calendar.get(Calendar.MONTH); + int d = calendar.get(Calendar.DATE); + return String.format("%s/%s / %s", formatInt(m), formatInt(d), ws); } /** - * @return 判断一个时间是不是今年 + * format to HH + * + * @param i integer + * @return HH */ - public static boolean isCurrentYear(long when) { - android.text.format.Time time = new android.text.format.Time(); - time.set(when); - - int thenYear = time.year; - - time.set(System.currentTimeMillis()); - return (thenYear == time.year); + public static String formatInt(int i) { + return (i < 10 ? "0" : "") + i; } + /** - * 获取当前日期是星期几
    - * - * @param dt - * @return 当前日期是星期几 + * 智能格式化 */ - public static int getWeekOfDate(Date dt) { - Calendar cal = Calendar.getInstance(); - cal.setTime(dt); - int w = cal.get(Calendar.DAY_OF_WEEK) - 1; - if (w < 0) - w = 0; - return w; + public static String friendly_time3(String sdate) { + Calendar calendar = parseCalendar(sdate); + if (calendar == null) return sdate; + + Calendar mCurrentDate = Calendar.getInstance(); + SimpleDateFormat formatter = YYYYMMDDHHMMSS.get(); + + int hour = calendar.get(Calendar.HOUR_OF_DAY); + String s = hour >= 0 && hour < 12 ? "上午" : "下午"; + s += " HH:mm"; + + if (mCurrentDate.get(Calendar.DATE) == calendar.get(Calendar.DATE)) { + formatter.applyPattern(s); + } else if (mCurrentDate.get(Calendar.DATE) - calendar.get(Calendar.DATE) == 1) { + formatter.applyPattern("昨天 " + s); + } else if (mCurrentDate.get(Calendar.YEAR) == calendar.get(Calendar.YEAR)) { + formatter.applyPattern("MM-dd " + s); + } else { + formatter.applyPattern("YYYY-MM-dd " + s); + } + return formatter.format(calendar.getTime()); } + /** * 判断给定字符串时间是否为今日 - * + * * @param sdate * @return boolean */ public static boolean isToday(String sdate) { - boolean b = false; Date time = toDate(sdate); Date today = new Date(); if (time != null) { - String nowDate = dateFormater2.get().format(today); - String timeDate = dateFormater2.get().format(time); + String nowDate = YYYYMMDD.get().format(today); + String timeDate = YYYYMMDD.get().format(time); if (nowDate.equals(timeDate)) { - b = true; + return true; } } - return b; + return false; } /** - * 返回long类型的今天的日期 - * + * 是否是相同的一天 + * + * @param sdate1 sdate1 + * @param sdate2 sdate2 * @return */ - public static long getToday() { - Calendar cal = Calendar.getInstance(); - String curDate = dateFormater2.get().format(cal.getTime()); - curDate = curDate.replace("-", ""); - return Long.parseLong(curDate); + public static boolean isSameDay(String sdate1, String sdate2) { + if (TextUtils.isEmpty(sdate1) || TextUtils.isEmpty(sdate2)) { + return false; + } + Date date1 = toDate(sdate1); + Date date2 = toDate(sdate2); + if (date1 != null && date2 != null) { + String d1 = YYYYMMDD.get().format(date1); + String d2 = YYYYMMDD.get().format(date2); + if (d1.equals(d2)) { + return true; + } + } + return false; } - public static String getCurTimeStr() { - Calendar cal = Calendar.getInstance(); - String curDate = dateFormater.get().format(cal.getTime()); - return curDate; + public static String getCurrentTimeStr() { + return YYYYMMDDHHMMSS.get().format(new Date()); } /*** * 计算两个时间差,返回的是的秒s - * - * @author 火蚁 2015-2-9 下午4:50:06 - * - * @return long - * @param dete1 + * + * @param date1 * @param date2 * @return + * @author 火蚁 2015-2-9 下午4:50:06 */ - public static long calDateDifferent(String dete1, String date2) { - - long diff = 0; - - Date d1 = null; - Date d2 = null; - + public static long calDateDifferent(String date1, String date2) { try { - d1 = dateFormater.get().parse(dete1); - d2 = dateFormater.get().parse(date2); - + Date d1 = YYYYMMDDHHMMSS.get().parse(date1); + Date d2 = YYYYMMDDHHMMSS.get().parse(date2); // 毫秒ms - diff = d2.getTime() - d1.getTime(); - + long diff = d2.getTime() - d1.getTime(); + return diff / 1000; } catch (Exception e) { e.printStackTrace(); + return 0; } - - return diff / 1000; } /** * 判断给定字符串是否空白串。 空白串是指由空格、制表符、回车符、换行符组成的字符串 若输入字符串为null或空字符串,返回true - * + * * @param input * @return boolean */ + @Deprecated public static boolean isEmpty(String input) { if (input == null || "".equals(input)) return true; @@ -355,7 +390,7 @@ public class StringUtils { /** * 判断是不是一个合法的电子邮件地址 - * + * * @param email * @return */ @@ -367,7 +402,7 @@ public class StringUtils { /** * 判断一个url是否为图片url - * + * * @param url * @return */ @@ -379,7 +414,7 @@ public class StringUtils { /** * 判断是否为一个合法的url地址 - * + * * @param str * @return */ @@ -391,7 +426,7 @@ public class StringUtils { /** * 字符串转整数 - * + * * @param str * @param defValue * @return @@ -400,13 +435,14 @@ public class StringUtils { try { return Integer.parseInt(str); } catch (Exception e) { + Log.d("oschina", e.getMessage()); } return defValue; } /** * 对象转整数 - * + * * @param obj * @return 转换异常返回 0 */ @@ -418,7 +454,7 @@ public class StringUtils { /** * 对象转整数 - * + * * @param obj * @return 转换异常返回 0 */ @@ -432,7 +468,7 @@ public class StringUtils { /** * 字符串转布尔值 - * + * * @param b * @return 转换异常返回 false */ @@ -450,38 +486,25 @@ public class StringUtils { /** * 将一个InputStream流转换成字符串 - * + * * @param is * @return */ public static String toConvertString(InputStream is) { - StringBuffer res = new StringBuffer(); - InputStreamReader isr = new InputStreamReader(is); - BufferedReader read = new BufferedReader(isr); + StringBuilder res = new StringBuilder(); + BufferedReader read = new BufferedReader(new InputStreamReader(is)); try { String line; - line = read.readLine(); - while (line != null) { - res.append(line + "
    "); - line = read.readLine(); + while ((line = read.readLine()) != null) { + res.append(line).append("
    "); } } catch (IOException e) { e.printStackTrace(); } finally { try { - if (null != isr) { - isr.close(); - isr.close(); - } - if (null != read) { - read.close(); - read = null; - } - if (null != is) { - is.close(); - is = null; - } + read.close(); } catch (IOException e) { + e.printStackTrace(); } } return res.toString(); @@ -489,39 +512,36 @@ public class StringUtils { /*** * 截取字符串 - * - * @param start - * 从那里开始,0算起 - * @param num - * 截取多少个 - * @param str - * 截取的字符串 + * + * @param start 从那里开始,0算起 + * @param num 截取多少个 + * @param str 截取的字符串 * @return */ public static String getSubString(int start, int num, String str) { if (str == null) { return ""; } - int leng = str.length(); + int length = str.length(); if (start < 0) { start = 0; } - if (start > leng) { - start = leng; + if (start > length) { + start = length; } if (num < 0) { num = 1; } int end = start + num; - if (end > leng) { - end = leng; + if (end > length) { + end = length; } return str.substring(start, end); } /** * 获取当前时间为每年第几周 - * + * * @return */ public static int getWeekOfYear() { @@ -530,7 +550,7 @@ public class StringUtils { /** * 获取当前时间为每年第几周 - * + * * @param date * @return */ @@ -561,8 +581,7 @@ public class StringUtils { * 返回当前系统时间 */ public static String getDataTime(String format) { - SimpleDateFormat df = new SimpleDateFormat(format); - return df.format(new Date()); + return new SimpleDateFormat(format, Locale.getDefault()).format(new Date()); } } diff --git a/app/src/main/java/net/oschina/app/util/SynchronizeController.java b/app/src/main/java/net/oschina/app/util/SynchronizeController.java index 203458bf3eb5f31200d027b7cf15158bc397bfb5..892b8c1e7ea896f131b72a8243439722bcff94c6 100644 --- a/app/src/main/java/net/oschina/app/util/SynchronizeController.java +++ b/app/src/main/java/net/oschina/app/util/SynchronizeController.java @@ -1,24 +1,24 @@ package net.oschina.app.util; -import java.util.List; +import android.app.Activity; + +import com.loopj.android.http.AsyncHttpClient; +import com.loopj.android.http.AsyncHttpResponseHandler; -import net.oschina.app.AppContext; import net.oschina.app.api.ApiHttpClient; import net.oschina.app.bean.NotebookData; import net.oschina.app.db.NoteDatabase; - -import cz.msebera.android.httpclient.Header; +import net.oschina.app.improve.account.AccountHelper; import org.kymjs.kjframe.utils.KJLoger; import org.kymjs.kjframe.utils.SystemTool; -import android.app.Activity; +import java.util.List; + +import cz.msebera.android.httpclient.Header; import cz.msebera.android.httpclient.entity.StringEntity; import cz.msebera.android.httpclient.protocol.HTTP; -import com.loopj.android.http.AsyncHttpClient; -import com.loopj.android.http.AsyncHttpResponseHandler; - /** * 一个文件云同步解决方案(便签同步) * @@ -72,7 +72,7 @@ public class SynchronizeController { // sPreviousRefreshTime = currentTime; } - int uid = AppContext.getInstance().getLoginUid(); + int uid = (int) AccountHelper.getUserId(); StringBuilder jsonData = new StringBuilder(); int size = localDatas.size(); jsonData.append("{\"uid\":").append(uid).append(",\"stickys\":["); @@ -106,7 +106,7 @@ public class SynchronizeController { } jsonData.append("]}"); - KJLoger.debug("==" + jsonData.toString()); +// KJLoger.debug("==" + jsonData.toString()); AsyncHttpClient client = ApiHttpClient.getHttpClient(); client.addHeader("Content-Type", "application/json; charset=UTF-8"); @@ -131,6 +131,5 @@ public class SynchronizeController { } }); - ApiHttpClient.setHttpClient(client); } } diff --git a/app/src/main/java/net/oschina/app/util/TDevice.java b/app/src/main/java/net/oschina/app/util/TDevice.java index 8ff3eb53f8744ddd20319400d3eff0bfbf51d788..268d6e65db49fe971cfc0a07830c3a86020acbd9 100644 --- a/app/src/main/java/net/oschina/app/util/TDevice.java +++ b/app/src/main/java/net/oschina/app/util/TDevice.java @@ -1,99 +1,48 @@ package net.oschina.app.util; -import java.io.File; -import java.lang.reflect.Field; -import java.text.NumberFormat; -import java.util.List; -import java.util.UUID; - -import net.oschina.app.AppContext; -import net.oschina.app.R; -import net.oschina.app.base.BaseApplication; - -import android.annotation.TargetApi; import android.app.Activity; -import android.app.Dialog; import android.content.ActivityNotFoundException; import android.content.ClipboardManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.SharedPreferences; -import android.content.pm.PackageInfo; import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; -import android.graphics.Point; +import android.content.res.Configuration; +import android.graphics.Rect; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.Uri; -import android.os.Build; -import android.os.Environment; -import android.os.PowerManager; -import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.DisplayMetrics; -import android.util.TypedValue; -import android.view.Display; import android.view.View; -import android.view.ViewConfiguration; -import android.view.WindowManager; +import android.view.Window; import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; -@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) -public class TDevice { - - // 手机网络类型 - public static final int NETTYPE_WIFI = 0x01; - public static final int NETTYPE_CMWAP = 0x02; - public static final int NETTYPE_CMNET = 0x03; - - public static boolean GTE_HC; - public static boolean GTE_ICS; - public static boolean PRE_HC; - private static Boolean _hasBigScreen = null; - private static Boolean _hasCamera = null; - private static Boolean _isTablet = null; - private static Integer _loadFactor = null; - - private static int _pageSize = -1; - public static float displayDensity = 0.0F; - - static { - GTE_ICS = Build.VERSION.SDK_INT >= 14; - GTE_HC = Build.VERSION.SDK_INT >= 11; - PRE_HC = Build.VERSION.SDK_INT < 11; - } +import net.oschina.app.AppContext; +import net.oschina.app.R; +import net.oschina.app.base.BaseApplication; - public TDevice() { - } +import java.io.File; +import java.util.List; - public static float dpToPixel(float dp) { - return dp * (getDisplayMetrics().densityDpi / 160F); - } +/** + * + * @updator thanatosx + */ +public class TDevice { - public static int getDefaultLoadFactor() { - if (_loadFactor == null) { - Integer integer = Integer.valueOf(0xf & BaseApplication.context() - .getResources().getConfiguration().screenLayout); - _loadFactor = integer; - _loadFactor = Integer.valueOf(Math.max(integer.intValue(), 1)); - } - return _loadFactor.intValue(); + public static float dp2px(float dp) { + return dp * getDisplayMetrics().density; } - public static float getDensity() { - if (displayDensity == 0.0) - displayDensity = getDisplayMetrics().density; - return displayDensity; + public static float px2dp(float px) { + return px / getDisplayMetrics().density; } public static DisplayMetrics getDisplayMetrics() { - DisplayMetrics displaymetrics = new DisplayMetrics(); - ((WindowManager) BaseApplication.context().getSystemService( - Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics( - displaymetrics); - return displaymetrics; + return BaseApplication.context().getResources().getDisplayMetrics(); } public static float getScreenHeight() { @@ -104,259 +53,85 @@ public class TDevice { return getDisplayMetrics().widthPixels; } - public static int[] getRealScreenSize(Activity activity) { - int[] size = new int[2]; - int screenWidth = 0, screenHeight = 0; - WindowManager w = activity.getWindowManager(); - Display d = w.getDefaultDisplay(); - DisplayMetrics metrics = new DisplayMetrics(); - d.getMetrics(metrics); - // since SDK_INT = 1; - screenWidth = metrics.widthPixels; - screenHeight = metrics.heightPixels; - // includes window decorations (statusbar bar/menu bar) - if (Build.VERSION.SDK_INT >= 14 && Build.VERSION.SDK_INT < 17) - try { - screenWidth = (Integer) Display.class.getMethod("getRawWidth") - .invoke(d); - screenHeight = (Integer) Display.class - .getMethod("getRawHeight").invoke(d); - } catch (Exception ignored) { - } - // includes window decorations (statusbar bar/menu bar) - if (Build.VERSION.SDK_INT >= 17) - try { - Point realSize = new Point(); - Display.class.getMethod("getRealSize", Point.class).invoke(d, - realSize); - screenWidth = realSize.x; - screenHeight = realSize.y; - } catch (Exception ignored) { - } - size[0] = screenWidth; - size[1] = screenHeight; - return size; - } - - public static int getStatusBarHeight() { - Class c = null; - Object obj = null; - Field field = null; - int x = 0; - try { - c = Class.forName("com.android.internal.R$dimen"); - obj = c.newInstance(); - field = c.getField("status_bar_height"); - x = Integer.parseInt(field.get(obj).toString()); - return BaseApplication.context().getResources() - .getDimensionPixelSize(x); - } catch (Exception e) { - e.printStackTrace(); - } - return 0; - } - - public static String getUdid() { - String udid = BaseApplication.getPreferences().getString("udid", ""); - if (udid.length() == 0) { - SharedPreferences.Editor editor = BaseApplication.getPreferences() - .edit(); - udid = String.format("%s", UUID.randomUUID()); - editor.putString("udid", udid); - editor.commit(); - } - return udid; - } - - public static boolean hasBigScreen() { - boolean flag = true; - if (_hasBigScreen == null) { - boolean flag1; - if ((0xf & BaseApplication.context().getResources() - .getConfiguration().screenLayout) >= 3) - flag1 = flag; - else - flag1 = false; - Boolean boolean1 = Boolean.valueOf(flag1); - _hasBigScreen = boolean1; - if (!boolean1.booleanValue()) { - if (getDensity() <= 1.5F) - flag = false; - _hasBigScreen = Boolean.valueOf(flag); - } - } - return _hasBigScreen.booleanValue(); - } - - public static final boolean hasCamera() { - if (_hasCamera == null) { - PackageManager pckMgr = BaseApplication.context() - .getPackageManager(); - boolean flag = pckMgr - .hasSystemFeature("android.hardware.camera.front"); - boolean flag1 = pckMgr.hasSystemFeature("android.hardware.camera"); - boolean flag2; - if (flag || flag1) - flag2 = true; - else - flag2 = false; - _hasCamera = Boolean.valueOf(flag2); - } - return _hasCamera.booleanValue(); - } - - public static boolean hasHardwareMenuKey(Context context) { - boolean flag = false; - if (PRE_HC) - flag = true; - else if (GTE_ICS) { - flag = ViewConfiguration.get(context).hasPermanentMenuKey(); - } else - flag = false; - return flag; + public static int getStatusBarHeight(Activity context) { + Rect rectangle = new Rect(); + Window window = context.getWindow(); + window.getDecorView().getWindowVisibleDisplayFrame(rectangle); + return rectangle.top; } public static boolean hasInternet() { - boolean flag; - if (((ConnectivityManager) BaseApplication.context().getSystemService( - "connectivity")).getActiveNetworkInfo() != null) - flag = true; - else - flag = false; - return flag; - } - - public static boolean gotoGoogleMarket(Activity activity, String pck) { - try { - Intent intent = new Intent(); - intent.setPackage("com.android.vending"); - intent.setAction(Intent.ACTION_VIEW); - intent.setData(Uri.parse("market://details?id=" + pck)); - activity.startActivity(intent); - return true; - } catch (Exception e) { - e.printStackTrace(); - return false; - } - } - - public static boolean isPackageExist(String pckName) { - try { - PackageInfo pckInfo = BaseApplication.context().getPackageManager() - .getPackageInfo(pckName, 0); - if (pckInfo != null) - return true; - } catch (NameNotFoundException e) { - TLog.error(e.getMessage()); - } - return false; - } - - public static void hideAnimatedView(View view) { - if (PRE_HC && view != null) - view.setPadding(view.getWidth(), 0, 0, 0); - } - - public static void hideSoftKeyboard(View view) { - if (view == null) - return; - ((InputMethodManager) BaseApplication.context().getSystemService( - Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow( - view.getWindowToken(), 0); - } - - public static boolean isLandscape() { - boolean flag; - if (BaseApplication.context().getResources().getConfiguration().orientation == 2) - flag = true; - else - flag = false; - return flag; + ConnectivityManager cm = (ConnectivityManager) BaseApplication.context() + .getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo info = cm.getActiveNetworkInfo(); + return info != null && info.isAvailable() && info.isConnected(); } public static boolean isPortrait() { - boolean flag = true; - if (BaseApplication.context().getResources().getConfiguration().orientation != 1) - flag = false; - return flag; + return BaseApplication.context().getResources().getConfiguration() + .orientation == Configuration.ORIENTATION_PORTRAIT; } - public static boolean isTablet() { - if (_isTablet == null) { - boolean flag; - if ((0xf & BaseApplication.context().getResources() - .getConfiguration().screenLayout) >= 3) - flag = true; - else - flag = false; - _isTablet = Boolean.valueOf(flag); + /** + * 打开或关闭键盘 + */ + public static void startOrCloseKeyboard(View view) { + InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + // 得到InputMethodManager的实例 + if (imm.isActive()) { + // 如果开启 + imm.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, + InputMethodManager.HIDE_NOT_ALWAYS); } - return _isTablet.booleanValue(); - } - - public static float pixelsToDp(float f) { - return f / (getDisplayMetrics().densityDpi / 160F); - } - - public static void showAnimatedView(View view) { - if (PRE_HC && view != null) - view.setPadding(0, 0, 0, 0); } - public static void showSoftKeyboard(Dialog dialog) { - dialog.getWindow().setSoftInputMode(4); + public static void closeKeyboard(EditText view) { + view.clearFocus(); + InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.RESULT_UNCHANGED_SHOWN); } - public static void showSoftKeyboard(View view) { - ((InputMethodManager) BaseApplication.context().getSystemService( - Context.INPUT_METHOD_SERVICE)).showSoftInput(view, - InputMethodManager.SHOW_FORCED); + public static void openKeyboard(View view) { + InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS); } - public static void toogleSoftKeyboard(View view) { - ((InputMethodManager) BaseApplication.context().getSystemService( - Context.INPUT_METHOD_SERVICE)).toggleSoftInput(0, - InputMethodManager.HIDE_NOT_ALWAYS); - } - - public static boolean isSdcardReady() { - return Environment.MEDIA_MOUNTED.equals(Environment - .getExternalStorageState()); + /** + * 平板电脑? + * + * @return ?? + */ + public static boolean isTablet() { + int s = BaseApplication.context().getResources().getConfiguration().screenLayout; + s &= Configuration.SCREENLAYOUT_SIZE_MASK; + return s >= Configuration.SCREENLAYOUT_SIZE_LARGE; } - public static String getCurCountryLan() { - return BaseApplication.context().getResources().getConfiguration().locale - .getLanguage() - + "-" - + BaseApplication.context().getResources().getConfiguration().locale - .getCountry(); - } + public static void hideSoftKeyboard(View view) { + if (view == null) return; + View mFocusView = view; - public static boolean isZhCN() { - String lang = BaseApplication.context().getResources() - .getConfiguration().locale.getCountry(); - if (lang.equalsIgnoreCase("CN")) { - return true; + Context context = view.getContext(); + if (context != null && context instanceof Activity) { + Activity activity = ((Activity) context); + mFocusView = activity.getCurrentFocus(); } - return false; + if (mFocusView == null) return; + mFocusView.clearFocus(); + InputMethodManager manager = (InputMethodManager) mFocusView.getContext() + .getSystemService(Context.INPUT_METHOD_SERVICE); + manager.hideSoftInputFromWindow(mFocusView.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); } - public static String percent(double p1, double p2) { - String str; - double p3 = p1 / p2; - NumberFormat nf = NumberFormat.getPercentInstance(); - nf.setMinimumFractionDigits(2); - str = nf.format(p3); - return str; - } + public static void showSoftKeyboard(View view) { + if (view == null) return; + view.setFocusable(true); + view.setFocusableInTouchMode(true); + if (!view.isFocused()) view.requestFocus(); - public static String percent2(double p1, double p2) { - String str; - double p3 = p1 / p2; - NumberFormat nf = NumberFormat.getPercentInstance(); - nf.setMinimumFractionDigits(0); - str = nf.format(p3); - return str; + InputMethodManager inputMethodManager = (InputMethodManager) view.getContext() + .getSystemService(Context.INPUT_METHOD_SERVICE); + inputMethodManager.showSoftInput(view, 0); } public static void gotoMarket(Context context, String pck) { @@ -364,8 +139,7 @@ public class TDevice { AppContext.showToast("你手机中没有安装应用市场!"); return; } - Intent intent = new Intent(); - intent.setAction(Intent.ACTION_VIEW); + Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse("market://details?id=" + pck)); if (intent.resolveActivity(context.getPackageManager()) != null) { context.startActivity(intent); @@ -373,104 +147,44 @@ public class TDevice { } public static boolean isHaveMarket(Context context) { - Intent intent = new Intent(); - intent.setAction("android.intent.action.MAIN"); - intent.addCategory("android.intent.category.APP_MARKET"); + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(Intent.CATEGORY_APP_MARKET); PackageManager pm = context.getPackageManager(); List infos = pm.queryIntentActivities(intent, 0); return infos.size() > 0; } public static void openAppInMarket(Context context) { - if (context != null) { - String pckName = context.getPackageName(); - try { - gotoMarket(context, pckName); - } catch (Exception ex) { - try { - String otherMarketUri = "http://market.android.com/details?id=" - + pckName; - Intent intent = new Intent(Intent.ACTION_VIEW, - Uri.parse(otherMarketUri)); - context.startActivity(intent); - } catch (Exception e) { - - } - } - } - } - - public static void setFullScreen(Activity activity) { - WindowManager.LayoutParams params = activity.getWindow() - .getAttributes(); - params.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN; - activity.getWindow().setAttributes(params); - activity.getWindow().addFlags( - WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); - } - - public static void cancelFullScreen(Activity activity) { - WindowManager.LayoutParams params = activity.getWindow() - .getAttributes(); - params.flags &= (~WindowManager.LayoutParams.FLAG_FULLSCREEN); - activity.getWindow().setAttributes(params); - activity.getWindow().clearFlags( - WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); - } - - public static PackageInfo getPackageInfo(String pckName) { - try { - return BaseApplication.context().getPackageManager() - .getPackageInfo(pckName, 0); - } catch (NameNotFoundException e) { - TLog.error(e.getMessage()); - } - return null; + if (context == null) return; + String pckName = context.getPackageName(); + gotoMarket(context, pckName); } public static int getVersionCode() { - int versionCode = 0; - try { - versionCode = BaseApplication - .context() - .getPackageManager() - .getPackageInfo(BaseApplication.context().getPackageName(), - 0).versionCode; - } catch (PackageManager.NameNotFoundException ex) { - versionCode = 0; - } - return versionCode; + return getVersionCode(BaseApplication.context().getPackageName()); } public static int getVersionCode(String packageName) { - int versionCode = 0; try { - versionCode = BaseApplication.context().getPackageManager() - .getPackageInfo(packageName, 0).versionCode; + return BaseApplication.context() + .getPackageManager() + .getPackageInfo(packageName, 0) + .versionCode; } catch (PackageManager.NameNotFoundException ex) { - versionCode = 0; + return 0; } - return versionCode; } public static String getVersionName() { - String name = ""; try { - name = BaseApplication + return BaseApplication .context() .getPackageManager() - .getPackageInfo(BaseApplication.context().getPackageName(), - 0).versionName; + .getPackageInfo(BaseApplication.context().getPackageName(), 0) + .versionName; } catch (PackageManager.NameNotFoundException ex) { - name = ""; + return "undefined version name"; } - return name; - } - - public static boolean isScreenOn() { - PowerManager pm = (PowerManager) BaseApplication.context() - .getSystemService(Context.POWER_SERVICE); - return pm.isScreenOn(); } public static void installAPK(Context context, File file) { @@ -479,196 +193,45 @@ public class TDevice { Intent intent = new Intent(); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setAction(Intent.ACTION_VIEW); - intent.setDataAndType(Uri.fromFile(file), - "application/vnd.android.package-archive"); - context.startActivity(intent); - } - - public static Intent getInstallApkIntent(File file) { - Intent intent = new Intent(); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.setAction(Intent.ACTION_VIEW); - intent.setDataAndType(Uri.fromFile(file), - "application/vnd.android.package-archive"); - return intent; - } - - public static void openDial(Context context, String number) { - Uri uri = Uri.parse("tel:" + number); - Intent it = new Intent(Intent.ACTION_DIAL, uri); - context.startActivity(it); - } - - public static void openSMS(Context context, String smsBody, String tel) { - Uri uri = Uri.parse("smsto:" + tel); - Intent it = new Intent(Intent.ACTION_SENDTO, uri); - it.putExtra("sms_body", smsBody); - context.startActivity(it); - } - - public static void openDail(Context context) { - Intent intent = new Intent(Intent.ACTION_DIAL); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive"); context.startActivity(intent); } - public static void openSendMsg(Context context) { - Uri uri = Uri.parse("smsto:"); - Intent intent = new Intent(Intent.ACTION_SENDTO, uri); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); - } - - public static void openCamera(Context context) { - Intent intent = new Intent(); // 调用照相机 - intent.setAction("android.media.action.STILL_IMAGE_CAMERA"); - intent.setFlags(0x34c40000); - context.startActivity(intent); - } - - public static String getIMEI() { - TelephonyManager tel = (TelephonyManager) BaseApplication.context() - .getSystemService(Context.TELEPHONY_SERVICE); - return tel.getDeviceId(); - } - - public static String getPhoneType() { - return android.os.Build.MODEL; - } - - public static void openApp(Context context, String packageName) { - Intent mainIntent = BaseApplication.context().getPackageManager() - .getLaunchIntentForPackage(packageName); - if (mainIntent == null) { - mainIntent = new Intent(packageName); - } else { - TLog.log("Action:" + mainIntent.getAction()); - } - context.startActivity(mainIntent); - } - - public static boolean openAppActivity(Context context, String packageName, + public static boolean openAppActivity(Context context, + String packageName, String activityName) { Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_LAUNCHER); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); ComponentName cn = new ComponentName(packageName, activityName); intent.setComponent(cn); try { context.startActivity(intent); return true; - } catch (Exception e) { + }catch (ActivityNotFoundException e){ return false; } } public static boolean isWifiOpen() { - boolean isWifiConnect = false; ConnectivityManager cm = (ConnectivityManager) BaseApplication .context().getSystemService(Context.CONNECTIVITY_SERVICE); - // check the networkInfos numbers - NetworkInfo[] networkInfos = cm.getAllNetworkInfo(); - for (int i = 0; i < networkInfos.length; i++) { - if (networkInfos[i].getState() == NetworkInfo.State.CONNECTED) { - if (networkInfos[i].getType() == ConnectivityManager.TYPE_MOBILE) { - isWifiConnect = false; - } - if (networkInfos[i].getType() == ConnectivityManager.TYPE_WIFI) { - isWifiConnect = true; - } - } - } - return isWifiConnect; - } - - public static void uninstallApk(Context context, String packageName) { - if (isPackageExist(packageName)) { - Uri packageURI = Uri.parse("package:" + packageName); - Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, - packageURI); - context.startActivity(uninstallIntent); - } + NetworkInfo info = cm.getActiveNetworkInfo(); + if (info == null) return false; + if (!info.isAvailable() || !info.isConnected()) return false; + if (info.getType() != ConnectivityManager.TYPE_WIFI) return false; + return true; } @SuppressWarnings("deprecation") public static void copyTextToBoard(String string) { - if (TextUtils.isEmpty(string)) - return; + if (TextUtils.isEmpty(string)) return; ClipboardManager clip = (ClipboardManager) BaseApplication.context() .getSystemService(Context.CLIPBOARD_SERVICE); clip.setText(string); AppContext.showToast(R.string.copy_success); } - /** - * 发送邮件 - * - * @param context - * @param subject 主题 - * @param content 内容 - * @param emails 邮件地址 - */ - public static void sendEmail(Context context, String subject, - String content, String... emails) { - try { - Intent intent = new Intent(Intent.ACTION_SEND); - // 模拟器 - // intent.setType("text/plain"); - intent.setType("message/rfc822"); // 真机 - intent.putExtra(android.content.Intent.EXTRA_EMAIL, emails); - intent.putExtra(Intent.EXTRA_SUBJECT, subject); - intent.putExtra(Intent.EXTRA_TEXT, content); - context.startActivity(intent); - } catch (ActivityNotFoundException e) { - e.printStackTrace(); - } - } - - public static int getStatuBarHeight() { - Class c = null; - Object obj = null; - Field field = null; - int x = 0, sbar = 38;// 默认为38,貌似大部分是这样的 - try { - c = Class.forName("com.android.internal.R$dimen"); - obj = c.newInstance(); - field = c.getField("status_bar_height"); - x = Integer.parseInt(field.get(obj).toString()); - sbar = BaseApplication.context().getResources() - .getDimensionPixelSize(x); - - } catch (Exception e1) { - e1.printStackTrace(); - } - return sbar; - } - - public static int getActionBarHeight(Context context) { - int actionBarHeight = 0; - TypedValue tv = new TypedValue(); - if (context.getTheme().resolveAttribute(android.R.attr.actionBarSize, - tv, true)) - actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, - context.getResources().getDisplayMetrics()); - - if (actionBarHeight == 0 - && context.getTheme().resolveAttribute(R.attr.actionBarSize, - tv, true)) { - actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, - context.getResources().getDisplayMetrics()); - } - - return actionBarHeight; - } - - public static boolean hasStatusBar(Activity activity) { - WindowManager.LayoutParams attrs = activity.getWindow().getAttributes(); - if ((attrs.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) == WindowManager.LayoutParams.FLAG_FULLSCREEN) { - return false; - } else { - return true; - } - } - /** * 调用系统安装了的应用分享 * @@ -685,32 +248,4 @@ public class TDevice { context.startActivity(Intent.createChooser(intent, "选择分享")); } - /** - * 获取当前网络类型 - * - * @return 0:没有网络 1:WIFI网络 2:WAP网络 3:NET网络 - */ - public static int getNetworkType() { - int netType = 0; - ConnectivityManager connectivityManager = (ConnectivityManager) AppContext - .getInstance().getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); - if (networkInfo == null) { - return netType; - } - int nType = networkInfo.getType(); - if (nType == ConnectivityManager.TYPE_MOBILE) { - String extraInfo = networkInfo.getExtraInfo(); - if (!StringUtils.isEmpty(extraInfo)) { - if (extraInfo.toLowerCase().equals("cmnet")) { - netType = NETTYPE_CMNET; - } else { - netType = NETTYPE_CMWAP; - } - } - } else if (nType == ConnectivityManager.TYPE_WIFI) { - netType = NETTYPE_WIFI; - } - return netType; - } } diff --git a/app/src/main/java/net/oschina/app/util/TLog.java b/app/src/main/java/net/oschina/app/util/TLog.java index 5bc289c67bb29171478af496e0d9bddd992fdb54..5369ec13484eab868212809b3db85a10bd44c782 100644 --- a/app/src/main/java/net/oschina/app/util/TLog.java +++ b/app/src/main/java/net/oschina/app/util/TLog.java @@ -2,40 +2,37 @@ package net.oschina.app.util; import android.util.Log; +import net.oschina.app.BuildConfig; + + public class TLog { - public static final String LOG_TAG = "SIMICO"; - public static boolean DEBUG = true; - - public TLog() { - } - - public static final void analytics(String log) { - if (DEBUG) - Log.d(LOG_TAG, log); - } - - public static final void error(String log) { - if (DEBUG) - Log.e(LOG_TAG, "" + log); - } - - public static final void log(String log) { - if (DEBUG) - Log.i(LOG_TAG, log); - } - - public static final void log(String tag, String log) { - if (DEBUG) - Log.i(tag, log); - } - - public static final void logv(String log) { - if (DEBUG) - Log.v(LOG_TAG, log); - } - - public static final void warn(String log) { - if (DEBUG) - Log.w(LOG_TAG, log); - } + private static final String LOG_TAG = "OSChinaLog"; + private static boolean DEBUG = BuildConfig.DEBUG; + + private TLog() { + } + + public static void error(String log) { + if (DEBUG) Log.e(LOG_TAG, "" + log); + } + + public static void log(String log) { + if (DEBUG) Log.i(LOG_TAG, log); + } + + public static void log(String tag, String log) { + if (DEBUG) Log.i(tag, log); + } + + public static void d(String tag, String log) { + if (DEBUG) Log.d(tag, log); + } + + public static void e(String tag, String log) { + if (DEBUG) Log.e(tag, log); + } + + public static void i(String tag, String log) { + if (DEBUG) Log.i(tag, log); + } } diff --git a/app/src/main/java/net/oschina/app/util/ThemeSwitchUtils.java b/app/src/main/java/net/oschina/app/util/ThemeSwitchUtils.java index 7ddbb0f81f248caf117d1116b33e6ae8f991f838..adf9e375a66773f6218f846d129184e9f24c9690 100644 --- a/app/src/main/java/net/oschina/app/util/ThemeSwitchUtils.java +++ b/app/src/main/java/net/oschina/app/util/ThemeSwitchUtils.java @@ -1,8 +1,5 @@ package net.oschina.app.util; -import android.content.Context; - -import net.oschina.app.AppContext; import net.oschina.app.R; /** @@ -11,12 +8,8 @@ import net.oschina.app.R; */ public class ThemeSwitchUtils { - public static void switchTheme(Context context) { - - } - public static int getTitleReadedColor() { - if (AppContext.getNightModeSwitch()) { + if (false) { return R.color.night_infoTextColor; } else { return R.color.day_infoTextColor; @@ -24,7 +17,7 @@ public class ThemeSwitchUtils { } public static int getTitleUnReadedColor() { - if (AppContext.getNightModeSwitch()) { + if (false) { return R.color.night_textColor; } else { return R.color.day_textColor; @@ -32,10 +25,10 @@ public class ThemeSwitchUtils { } public static String getWebViewBodyString() { - if (AppContext.getNightModeSwitch()) { + if (false) { return "

    "; } else { - return "
    "; + return "
    "; } } } diff --git a/app/src/main/java/net/oschina/app/util/TimeZoneUtil.java b/app/src/main/java/net/oschina/app/util/TimeZoneUtil.java deleted file mode 100644 index 25a23d8122a33270b2cf9a26cc6972a4209b9a12..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/util/TimeZoneUtil.java +++ /dev/null @@ -1,40 +0,0 @@ -package net.oschina.app.util; - -import java.util.Date; -import java.util.TimeZone; - -/** - * @author HuangWenwei - * - * @date 2014年10月9日 - */ -public class TimeZoneUtil { - - /** - * 判断用户的设备时区是否为东八区(中国) 2014年7月31日 - * @return - */ - public static boolean isInEasternEightZones() { - boolean defaultVaule = true; - if (TimeZone.getDefault() == TimeZone.getTimeZone("GMT+08")) - defaultVaule = true; - else - defaultVaule = false; - return defaultVaule; - } - - /** - * 根据不同时区,转换时间 2014年7月31日 - * @param time - * @return - */ - public static Date transformTime(Date date, TimeZone oldZone, TimeZone newZone) { - Date finalDate = null; - if (date != null) { - int timeOffset = oldZone.getOffset(date.getTime()) - - newZone.getOffset(date.getTime()); - finalDate = new Date(date.getTime() - timeOffset); - } - return finalDate; - } -} diff --git a/app/src/main/java/net/oschina/app/util/UIHelper.java b/app/src/main/java/net/oschina/app/util/UIHelper.java index 03f3ce0b3742bc0116021bef01ef16cfb56be30e..8af90cf98d24ab1bac0abb492f1cfd0939a808f1 100644 --- a/app/src/main/java/net/oschina/app/util/UIHelper.java +++ b/app/src/main/java/net/oschina/app/util/UIHelper.java @@ -1,58 +1,54 @@ package net.oschina.app.util; import android.annotation.SuppressLint; -import android.app.Activity; -import android.content.ComponentName; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; -import android.content.ServiceConnection; import android.graphics.Color; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; -import android.os.IBinder; import android.os.Message; -import android.support.v4.app.Fragment; import android.text.Html; import android.text.Spannable; import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.Spanned; +import android.text.TextUtils; import android.text.style.AbsoluteSizeSpan; import android.text.style.ForegroundColorSpan; import android.view.View; import android.webkit.JavascriptInterface; import android.webkit.WebSettings; import android.webkit.WebView; -import android.webkit.WebViewClient; import android.widget.ZoomButtonsController; import com.dtr.zxing.activity.CaptureActivity; import net.oschina.app.AppConfig; import net.oschina.app.AppContext; -import net.oschina.app.base.BaseListFragment; +import net.oschina.app.api.remote.OSChinaApi; import net.oschina.app.bean.Active; -import net.oschina.app.bean.Comment; -import net.oschina.app.bean.Constants; -import net.oschina.app.bean.News; -import net.oschina.app.bean.Notice; -import net.oschina.app.bean.ShakeObject; +import net.oschina.app.bean.Banner; import net.oschina.app.bean.SimpleBackPage; -import net.oschina.app.bean.Tweet; import net.oschina.app.fragment.BrowserFragment; -import net.oschina.app.fragment.CommentFrament; -import net.oschina.app.fragment.FriendsFragment; -import net.oschina.app.fragment.MessageDetailFragment; import net.oschina.app.fragment.QuestionTagFragment; -import net.oschina.app.fragment.SoftWareTweetsFrament; -import net.oschina.app.interf.ICallbackResult; +import net.oschina.app.improve.account.activity.LoginActivity; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.bean.User; +import net.oschina.app.improve.detail.activities.BlogDetailActivity; +import net.oschina.app.improve.detail.activities.EventDetailActivity; +import net.oschina.app.improve.detail.activities.NewsDetailActivity; +import net.oschina.app.improve.detail.activities.QuestionDetailActivity; +import net.oschina.app.improve.detail.activities.SoftwareDetailActivity; +import net.oschina.app.improve.detail.activities.TranslateDetailActivity; +import net.oschina.app.improve.tweet.activities.TweetDetailActivity; +import net.oschina.app.improve.user.activities.OtherUserHomeActivity; +import net.oschina.app.improve.user.activities.UserSendMessageActivity; +import net.oschina.app.improve.user.fragments.UserBlogFragment; +import net.oschina.app.improve.user.fragments.UserQuestionFragment; +import net.oschina.app.improve.utils.URLUtils; import net.oschina.app.interf.OnWebViewImageListener; -import net.oschina.app.service.DownloadService; -import net.oschina.app.service.DownloadService.DownloadBinder; -import net.oschina.app.service.NoticeService; import net.oschina.app.team.adapter.TeamMemberAdapter; import net.oschina.app.team.bean.Team; import net.oschina.app.team.bean.TeamActive; @@ -65,58 +61,56 @@ import net.oschina.app.team.fragment.TeamActiveFragment; import net.oschina.app.team.ui.TeamMainActivity; import net.oschina.app.team.ui.TeamNewIssueActivity; import net.oschina.app.ui.DetailActivity; -import net.oschina.app.ui.EventLocationActivity; -import net.oschina.app.ui.ImagePreviewActivity; -import net.oschina.app.ui.LoginActivity; +import net.oschina.app.ui.OSCPhotosActivity; import net.oschina.app.ui.SimpleBackActivity; -import net.oschina.app.ui.TweetActivity; -import net.oschina.app.viewpagerfragment.FriendsViewPagerFragment; import net.oschina.app.widget.AvatarView; -import org.json.JSONException; -import org.json.JSONObject; - -import java.net.URLDecoder; - /** * 界面帮助类 - * + * * @author FireAnt(http://my.oschina.net/LittleDY) * @version 创建时间:2014年10月10日 下午3:33:36 - * */ public class UIHelper { - /** 全局web样式 */ + /** + * 全局web样式 + */ // 链接样式文件,代码块高亮的处理 - public final static String linkCss = "" + public final static String linkCss = "" + "" + "" - + "" + + "" + "" - + "" - + "" - + "" - + ""; + + "" + + "" + + "" + + ""; public final static String WEB_STYLE = linkCss; - public static final String WEB_LOAD_IMAGES = ""; + public static final String WEB_LOAD_IMAGES = ""; private static final String SHOWIMAGE = "ima-api:action=showImage&data="; /** * 显示登录界面 - * + * * @param context */ public static void showLoginActivity(Context context) { - Intent intent = new Intent(context, LoginActivity.class); - context.startActivity(intent); + LoginActivity.show(context); } /** * 显示Team界面 - * + * * @param context */ public static void showTeamMainActivity(Context context) { @@ -126,62 +120,44 @@ public class UIHelper { /** * 显示新闻详情 - * + * * @param context * @param newsId */ - public static void showNewsDetail(Context context, int newsId, - int commentCount) { - Intent intent = new Intent(context, DetailActivity.class); - intent.putExtra("id", newsId); - intent.putExtra("comment_count", commentCount); - intent.putExtra(DetailActivity.BUNDLE_KEY_DISPLAY_TYPE, - DetailActivity.DISPLAY_NEWS); - context.startActivity(intent); + public static void showNewsDetail(Context context, long newsId, + int commentCount) { + NewsDetailActivity.show(context, newsId); } + /** * 显示博客详情 - * + * * @param context * @param blogId */ - public static void showBlogDetail(Context context, int blogId, int count) { - Intent intent = new Intent(context, DetailActivity.class); - intent.putExtra("id", blogId); - intent.putExtra("comment_count", count); - intent.putExtra(DetailActivity.BUNDLE_KEY_DISPLAY_TYPE, - DetailActivity.DISPLAY_BLOG); - context.startActivity(intent); + public static void showBlogDetail(Context context, long blogId) { + BlogDetailActivity.show(context, blogId); } /** * 显示帖子详情 - * + * * @param context * @param postId */ - public static void showPostDetail(Context context, int postId, int count) { - Intent intent = new Intent(context, DetailActivity.class); - intent.putExtra("id", postId); - intent.putExtra("comment_count", count); - intent.putExtra(DetailActivity.BUNDLE_KEY_DISPLAY_TYPE, - DetailActivity.DISPLAY_POST); - context.startActivity(intent); + public static void showPostDetail(Context context, long postId, int count) { + QuestionDetailActivity.show(context, postId); } /** * 显示活动详情 - * + * * @param context * @param eventId */ - public static void showEventDetail(Context context, int eventId) { - Intent intent = new Intent(context, DetailActivity.class); - intent.putExtra("id", eventId); - intent.putExtra(DetailActivity.BUNDLE_KEY_DISPLAY_TYPE, - DetailActivity.DISPLAY_EVENT); - context.startActivity(intent); + public static void showEventDetail(Context context, long eventId) { + EventDetailActivity.show(context, eventId); } /** @@ -196,96 +172,88 @@ public class UIHelper { showSimpleBack(context, SimpleBackPage.QUESTION_TAG, args); } - /** - * 显示动弹详情 - * - * @param context context - * @param tweetid 动弹的id - */ - public static void showTweetDetail(Context context, Tweet tweet, int tweetid) { - Intent intent = new Intent(context, DetailActivity.class); - Bundle bundle = new Bundle(); - bundle.putInt("tweet_id", tweetid); - bundle.putInt(DetailActivity.BUNDLE_KEY_DISPLAY_TYPE, - DetailActivity.DISPLAY_TWEET); - if (tweet != null) { - bundle.putParcelable("tweet", tweet); - } - intent.putExtras(bundle); - context.startActivity(intent); - } - - /** - * 显示软件详情 - * - * @param context - * @param ident - */ - public static void showSoftwareDetail(Context context, String ident) { - Intent intent = new Intent(context, DetailActivity.class); - intent.putExtra("ident", ident); - intent.putExtra(DetailActivity.BUNDLE_KEY_DISPLAY_TYPE, - DetailActivity.DISPLAY_SOFTWARE); - context.startActivity(intent); - } - public static void showSoftwareDetailById(Context context, int id) { - Intent intent = new Intent(context, DetailActivity.class); - intent.putExtra("id", id); - intent.putExtra("ident", ""); - intent.putExtra(DetailActivity.BUNDLE_KEY_DISPLAY_TYPE, - DetailActivity.DISPLAY_SOFTWARE); - context.startActivity(intent); + SoftwareDetailActivity.show(context, id); } /** - * 新闻超链接点击跳转 - * + * show detail method + * * @param context context - */ - public static void showNewsRedirect(Context context, News news) { - String url = news.getUrl(); - // 如果是活动则直接跳转活动详情页面 - String eventUrl = news.getNewType().getEventUrl(); - if (!StringUtils.isEmpty(eventUrl)) { - showEventDetail(context, - StringUtils.toInt(news.getNewType().getAttachment())); - return; + * @param type type + * @param id id + */ + public static void showDetail(Context context, int type, long id, String href) { + switch (type) { + case OSChinaApi.CATALOG_ALL: + //新闻链接 + showUrlRedirect(context, id, href); + break; + case OSChinaApi.CATALOG_SOFTWARE: + //软件推荐 + SoftwareDetailActivity.show(context, id); + //UIUtil.showSoftwareDetailById(context, (int) id); + break; + case OSChinaApi.CATALOG_QUESTION: + //问答 + QuestionDetailActivity.show(context, id); + break; + case OSChinaApi.CATALOG_BLOG: + //博客 + BlogDetailActivity.show(context, id); + break; + case OSChinaApi.CATALOG_TRANSLATION: + //4.翻译 + TranslateDetailActivity.show(context, id); + break; + case OSChinaApi.CATALOG_EVENT: + //活动 + EventDetailActivity.show(context, id); + break; + case OSChinaApi.CATALOG_TWEET: + // 动弹 + TweetDetailActivity.show(context, id); + break; + default: + //6.资讯 + NewsDetailActivity.show(context, id); + break; } - // url为空-旧方法 - if (StringUtils.isEmpty(url)) { - int newsId = news.getId(); - int newsType = news.getNewType().getType(); - String objId = news.getNewType().getAttachment(); - switch (newsType) { - case News.NEWSTYPE_NEWS: - showNewsDetail(context, newsId, news.getCommentCount()); + } + + public static void showBannerDetail(Context context, Banner banner) { + long newsId = banner.getId(); + switch (banner.getType()) { + case Banner.BANNER_TYPE_URL: + showNewsDetail(context, Integer.parseInt(String.valueOf(newsId)), 0); + break; + case Banner.BANNER_TYPE_SOFTWARE: + showSoftwareDetailById(context, Integer.parseInt(String.valueOf(newsId))); break; - case News.NEWSTYPE_SOFTWARE: - showSoftwareDetail(context, objId); + case Banner.BANNER_TYPE_POST: + showPostDetail(context, StringUtils.toInt(String.valueOf(newsId)), + 0); break; - case News.NEWSTYPE_POST: - showPostDetail(context, StringUtils.toInt(objId), - news.getCommentCount()); + case Banner.BANNER_TYPE_BLOG: + showBlogDetail(context, StringUtils.toLong(String.valueOf(newsId))); break; - case News.NEWSTYPE_BLOG: - showBlogDetail(context, StringUtils.toInt(objId), - news.getCommentCount()); + case Banner.BANNER_TYPE_EVENT: + EventDetailActivity.show(context, newsId); break; + case Banner.BANNER_TYPE_NEWS: + NewsDetailActivity.show(context, newsId); default: + showUrlRedirect(context, banner.getHref()); break; - } - } else { - showUrlRedirect(context, url); } } /** * 动态点击跳转到相关新闻、帖子等 - * + * * @param context context - * @param active 动态实体类 - * 0其他 1新闻 2帖子 3动弹 4博客 + * @param active 动态实体类 + * 0其他 1新闻 2帖子 3动弹 4博客 */ public static void showActiveRedirect(Context context, Active active) { String url = active.getUrl(); @@ -294,36 +262,37 @@ public class UIHelper { int id = active.getObjectId(); int catalog = active.getCatalog(); switch (catalog) { - case Active.CATALOG_OTHER: - // 其他-无跳转 - break; - case Active.CATALOG_NEWS: - showNewsDetail(context, id, active.getCommentCount()); - break; - case Active.CATALOG_POST: - showPostDetail(context, id, active.getCommentCount()); - break; - case Active.CATALOG_TWEET: - showTweetDetail(context, null, id); - break; - case Active.CATALOG_BLOG: - showBlogDetail(context, id, active.getCommentCount()); - break; - default: - break; + case Active.CATALOG_OTHER: + // 其他-无跳转 + break; + case Active.CATALOG_NEWS: + showNewsDetail(context, id, active.getCommentCount()); + break; + case Active.CATALOG_POST: + showPostDetail(context, id, active.getCommentCount()); + break; + case Active.CATALOG_TWEET: + TweetDetailActivity.show(context, id); +// showTweetDetail(context, null, id); + break; + case Active.CATALOG_BLOG: + showBlogDetail(context, id); + break; + default: + break; } } else { showUrlRedirect(context, url); } } - @SuppressLint({ "JavascriptInterface", "SetJavaScriptEnabled" }) + @SuppressLint({"JavascriptInterface", "SetJavaScriptEnabled"}) public static void initWebView(WebView webView) { WebSettings settings = webView.getSettings(); - settings.setDefaultFontSize(15); + settings.setDefaultFontSize(14); settings.setJavaScriptEnabled(true); - settings.setSupportZoom(true); - settings.setBuiltInZoomControls(true); + settings.setSupportZoom(false); + settings.setBuiltInZoomControls(false); int sysVersion = Build.VERSION.SDK_INT; if (sysVersion >= 11) { settings.setDisplayZoomControls(false); @@ -331,13 +300,13 @@ public class UIHelper { ZoomButtonsController zbc = new ZoomButtonsController(webView); zbc.getZoomControls().setVisibility(View.GONE); } - webView.setWebViewClient(UIHelper.getWebViewClient()); + //webView.setWebViewClient(UIUtil.getWebViewClient()); } /** * 添加网页的点击图片展示支持 */ - @SuppressLint({ "JavascriptInterface", "SetJavaScriptEnabled" }) + @SuppressLint({"JavascriptInterface", "SetJavaScriptEnabled"}) @JavascriptInterface public static void addWebImageShow(final Context cxt, WebView wv) { wv.getSettings().setJavaScriptEnabled(true); @@ -346,28 +315,12 @@ public class UIHelper { @JavascriptInterface public void showImagePreview(String bigImageUrl) { if (bigImageUrl != null && !StringUtils.isEmpty(bigImageUrl)) { - UIHelper.showImagePreview(cxt, new String[] { bigImageUrl }); + OSCPhotosActivity.showImagePreview(cxt, bigImageUrl); } } }, "mWebViewImageListener"); } - /** - * 获取webviewClient对象 - * - * @return - */ - public static WebViewClient getWebViewClient() { - - return new WebViewClient() { - @Override - public boolean shouldOverrideUrlLoading(WebView view, String url) { - showUrlRedirect(view.getContext(), url); - return true; - } - }; - } - public static String setHtmlCotentSupportImagePreview(String body) { // 读取用户设置:是否加载文章图片--默认有wifi下始终加载图片 if (AppContext.get(AppConfig.KEY_LOAD_IMAGE, true) @@ -383,189 +336,61 @@ public class UIHelper { // 过滤掉 img标签 body = body.replaceAll("<\\s*img\\s+([^>]*)\\s*>", ""); } + + // 过滤table的内部属性 + body = body.replaceAll("(]*?)\\s+border\\s*=\\s*\\S+", "$1"); + body = body.replaceAll("(]*?)\\s+cellspacing\\s*=\\s*\\S+", "$1"); + body = body.replaceAll("(]*?)\\s+cellpadding\\s*=\\s*\\S+", "$1"); + return body; } - /** - * 摇一摇点击跳转 - * - * @param obj - */ - public static void showUrlShake(Context context, ShakeObject obj) { - if (StringUtils.isEmpty(obj.getUrl())) { - if (ShakeObject.RANDOMTYPE_NEWS.equals(obj.getRandomtype())) { - UIHelper.showNewsDetail(context, - StringUtils.toInt(obj.getId()), - StringUtils.toInt(obj.getCommentCount())); - } - } else { - if (!StringUtils.isEmpty(obj.getUrl())) { - UIHelper.showUrlRedirect(context, obj.getUrl()); - } + private static void showUrlRedirect(Context context, long id, String url) { + if (url == null && id > 0) { + NewsDetailActivity.show(context, id); + return; } + + URLUtils.parseUrl(context, url); } /** * url跳转 - * + * * @param context * @param url */ public static void showUrlRedirect(Context context, String url) { - if (url == null) - return; - if (url.contains("city.oschina.net/")) { - int id = StringUtils.toInt(url.substring(url.lastIndexOf('/') + 1)); - UIHelper.showEventDetail(context, id); - return; - } - - if (url.startsWith(SHOWIMAGE)) { - String realUrl = url.substring(SHOWIMAGE.length()); - try { - JSONObject json = new JSONObject(realUrl); - int idx = json.optInt("index"); - String[] urls = json.getString("urls").split(","); - showImagePreview(context, idx, urls); - } catch (JSONException e) { - e.printStackTrace(); - } - return; - } - URLsUtils urls = URLsUtils.parseURL(url); - if (urls != null) { - showLinkRedirect(context, urls.getObjType(), urls.getObjId(), - urls.getObjKey()); - } else { - openBrowser(context, url); - } - } - - public static void showLinkRedirect(Context context, int objType, - int objId, String objKey) { - switch (objType) { - case URLsUtils.URL_OBJ_TYPE_NEWS: - showNewsDetail(context, objId, -1); - break; - case URLsUtils.URL_OBJ_TYPE_QUESTION: - showPostDetail(context, objId, 0); - break; - case URLsUtils.URL_OBJ_TYPE_QUESTION_TAG: - showPostListByTag(context, objKey); - break; - case URLsUtils.URL_OBJ_TYPE_SOFTWARE: - showSoftwareDetail(context, objKey); - break; - case URLsUtils.URL_OBJ_TYPE_ZONE: - showUserCenter(context, objId, objKey); - break; - case URLsUtils.URL_OBJ_TYPE_TWEET: - showTweetDetail(context, null, objId); - break; - case URLsUtils.URL_OBJ_TYPE_BLOG: - showBlogDetail(context, objId, 0); - break; - case URLsUtils.URL_OBJ_TYPE_OTHER: - openBrowser(context, objKey); - break; - case URLsUtils.URL_OBJ_TYPE_TEAM: - openSysBrowser(context, objKey); - break; - case URLsUtils.URL_OBJ_TYPE_GIT: - openSysBrowser(context, objKey); - break; - } + showUrlRedirect(context, 0, url); } /** * 打开内置浏览器 - * + * * @param context * @param url */ - public static void openBrowser(Context context, String url) { - - if (StringUtils.isImgUrl(url)) { - ImagePreviewActivity.showImagePrivew(context, 0, - new String[] { url }); - return; - } - - if (url.startsWith("http://www.oschina.net/tweet-topic/")) { - Bundle bundle = new Bundle(); - int i = url.lastIndexOf("/"); - if (i != -1) { - bundle.putString("topic", - URLDecoder.decode(url.substring(i + 1))); - } - UIHelper.showSimpleBack(context, SimpleBackPage.TWEET_TOPIC_LIST, - bundle); - return; - } + public static void openInternalBrowser(Context context, String url) { try { - // 启用外部浏览器 - // Uri uri = Uri.parse(url); - // Intent it = new Intent(Intent.ACTION_VIEW, uri); - // context.startActivity(it); Bundle bundle = new Bundle(); bundle.putString(BrowserFragment.BROWSER_KEY, url); showSimpleBack(context, SimpleBackPage.BROWSER, bundle); } catch (Exception e) { e.printStackTrace(); - AppContext.showToastShort("无法浏览此网页"); + openExternalBrowser(context, url); } } /** - * 打开系统中的浏览器 - * + * 打开外置的浏览器 + * * @param context * @param url */ - public static void openSysBrowser(Context context, String url) { - try { - Uri uri = Uri.parse(url); - Intent it = new Intent(Intent.ACTION_VIEW, uri); - context.startActivity(it); - } catch (Exception e) { - e.printStackTrace(); - AppContext.showToastShort("无法浏览此网页"); - } - } - - @JavascriptInterface - public static void showImagePreview(Context context, String[] imageUrls) { - ImagePreviewActivity.showImagePrivew(context, 0, imageUrls); - } - - @JavascriptInterface - public static void showImagePreview(Context context, int index, - String[] imageUrls) { - ImagePreviewActivity.showImagePrivew(context, index, imageUrls); - } - - public static void showSimpleBackForResult(Fragment fragment, - int requestCode, SimpleBackPage page, Bundle args) { - Intent intent = new Intent(fragment.getActivity(), - SimpleBackActivity.class); - intent.putExtra(SimpleBackActivity.BUNDLE_KEY_PAGE, page.getValue()); - intent.putExtra(SimpleBackActivity.BUNDLE_KEY_ARGS, args); - fragment.startActivityForResult(intent, requestCode); - } - - public static void showSimpleBackForResult(Activity context, - int requestCode, SimpleBackPage page, Bundle args) { - Intent intent = new Intent(context, SimpleBackActivity.class); - intent.putExtra(SimpleBackActivity.BUNDLE_KEY_PAGE, page.getValue()); - intent.putExtra(SimpleBackActivity.BUNDLE_KEY_ARGS, args); - context.startActivityForResult(intent, requestCode); - } - - public static void showSimpleBackForResult(Activity context, - int requestCode, SimpleBackPage page) { - Intent intent = new Intent(context, SimpleBackActivity.class); - intent.putExtra(SimpleBackActivity.BUNDLE_KEY_PAGE, page.getValue()); - context.startActivityForResult(intent, requestCode); + public static void openExternalBrowser(Context context, String url) { + Uri uri = Uri.parse(url); + Intent intent = new Intent(Intent.ACTION_VIEW, uri); + context.startActivity(Intent.createChooser(intent, "选择打开的应用")); } public static void showSimpleBack(Context context, SimpleBackPage page) { @@ -575,49 +400,15 @@ public class UIHelper { } public static void showSimpleBack(Context context, SimpleBackPage page, - Bundle args) { + Bundle args) { Intent intent = new Intent(context, SimpleBackActivity.class); intent.putExtra(SimpleBackActivity.BUNDLE_KEY_ARGS, args); intent.putExtra(SimpleBackActivity.BUNDLE_KEY_PAGE, page.getValue()); context.startActivity(intent); } - public static void showTweetActivity(Context context, SimpleBackPage page, - Bundle args) { - Intent intent = new Intent(context, TweetActivity.class); - intent.putExtra(TweetActivity.FROM_KEY, 1); - intent.putExtra(SimpleBackActivity.BUNDLE_KEY_ARGS, args); - intent.putExtra(SimpleBackActivity.BUNDLE_KEY_PAGE, page.getValue()); - context.startActivity(intent); - } - - public static void showComment(Context context, int id, int catalog) { - Intent intent = new Intent(context, DetailActivity.class); - intent.putExtra(CommentFrament.BUNDLE_KEY_ID, id); - intent.putExtra(CommentFrament.BUNDLE_KEY_CATALOG, catalog); - intent.putExtra(DetailActivity.BUNDLE_KEY_DISPLAY_TYPE, - DetailActivity.DISPLAY_COMMENT); - context.startActivity(intent); - } - - public static void showSoftWareTweets(Context context, int id) { - Bundle args = new Bundle(); - args.putInt(SoftWareTweetsFrament.BUNDLE_KEY_ID, id); - showSimpleBack(context, SimpleBackPage.SOFTWARE_TWEETS, args); - } - - public static void showBlogComment(Context context, int id, int ownerId) { - Intent intent = new Intent(context, DetailActivity.class); - intent.putExtra(CommentFrament.BUNDLE_KEY_ID, id); - intent.putExtra(CommentFrament.BUNDLE_KEY_OWNER_ID, ownerId); - intent.putExtra(CommentFrament.BUNDLE_KEY_BLOG, true); - intent.putExtra(DetailActivity.BUNDLE_KEY_DISPLAY_TYPE, - DetailActivity.DISPLAY_COMMENT); - context.startActivity(intent); - } - public static SpannableString parseActiveAction(int objecttype, - int objectcatalog, String objecttitle) { + int objectcatalog, String objecttitle) { String title = ""; int start = 0; int end = 0; @@ -674,13 +465,13 @@ public class UIHelper { /** * 组合动态的回复文本 - * + * * @param name * @param body * @return */ public static SpannableStringBuilder parseActiveReply(String name, - String body) { + String body) { Spanned span = Html.fromHtml(body.trim()); SpannableStringBuilder sp = new SpannableStringBuilder(name + ":"); sp.append(span); @@ -693,117 +484,64 @@ public class UIHelper { return sp; } - /** - * 发送App异常崩溃报告 - * - * @param context - * @param crashReport - */ - public static void sendAppCrashReport(final Context context) { - - DialogHelp.getConfirmDialog(context, "程序发生异常", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - // 退出 - System.exit(-1); - } - }).show(); - } - - /** - * 发送通知广播 - * - * @param context - * @param notice - */ - public static void sendBroadCast(Context context, Notice notice) { - if (!((AppContext) context.getApplicationContext()).isLogin() - || notice == null) - return; - Intent intent = new Intent(Constants.INTENT_ACTION_NOTICE); - Bundle bundle = new Bundle(); - bundle.putSerializable("notice_bean", notice); - intent.putExtras(bundle); - context.sendBroadcast(intent); - } - - /** - * 发送通知广播 - * - * @param context - */ - public static void sendBroadcastForNotice(Context context) { - Intent intent = new Intent(NoticeService.INTENT_ACTION_BROADCAST); - context.sendBroadcast(intent); - } - /** * 显示用户中心页面 - * + * * @param context * @param hisuid * @param hisuid * @param hisname */ - public static void showUserCenter(Context context, int hisuid, - String hisname) { + public static void showUserCenter(Context context, long hisuid, + String hisname) { if (hisuid == 0 && hisname.equalsIgnoreCase("匿名")) { AppContext.showToast("提醒你,该用户为非会员"); return; } - Bundle args = new Bundle(); - args.putInt("his_id", hisuid); - args.putString("his_name", hisname); - showSimpleBack(context, SimpleBackPage.USER_CENTER, args); + OtherUserHomeActivity.show(context, hisuid); } /** * 显示用户的博客列表 - * + * * @param context * @param uid */ - public static void showUserBlog(Context context, int uid) { + public static void showUserBlog(Context context, long uid) { Bundle args = new Bundle(); - args.putInt(BaseListFragment.BUNDLE_KEY_CATALOG, uid); + args.putLong(UserBlogFragment.BUNDLE_KEY_USER_ID, uid); showSimpleBack(context, SimpleBackPage.USER_BLOG, args); } + /** + * 显示用户的问答列表 + * + * @param context context + * @param uid authorId + */ + public static void showUserQuestion(Context context, long uid) { + Bundle args = new Bundle(); + args.putLong(UserQuestionFragment.BUNDLE_KEY_AUTHOR_ID, uid); + showSimpleBack(context, SimpleBackPage.MY_QUESTION, args); + } + /** * 显示用户头像大图 - * + * * @param context * @param avatarUrl */ public static void showUserAvatar(Context context, String avatarUrl) { - if (StringUtils.isEmpty(avatarUrl)) { + if (TextUtils.isEmpty(avatarUrl)) { return; } String url = AvatarView.getLargeAvatar(avatarUrl); - ImagePreviewActivity.showImagePrivew(context, 0, new String[] { url }); - } - - /** - * 显示登陆用户的个人中心页面 - * - * @param context - */ - public static void showMyInformation(Context context) { - showSimpleBack(context, SimpleBackPage.MY_INFORMATION); - } - - /** - * 显示我的所有动态 - * - * @param context - */ - public static void showMyActive(Context context) { - showSimpleBack(context, SimpleBackPage.MY_ACTIVE); + OSCPhotosActivity.showImagePreview(context, url); } /** * 显示扫一扫界面 - * + * * @param context */ public static void showScanActivity(Context context) { @@ -811,75 +549,33 @@ public class UIHelper { context.startActivity(intent); } - /** - * 显示用户的消息中心 - * - * @param context - */ - public static void showMyMes(Context context) { - showSimpleBack(context, SimpleBackPage.MY_MES); - } - - /** - * 显示用户收藏界面 - * - * @param context - */ - public static void showUserFavorite(Context context, int uid) { - - Bundle args = new Bundle(); - args.putInt(BaseListFragment.BUNDLE_KEY_CATALOG, uid); - showSimpleBack(context, SimpleBackPage.USER_FAVORITE); - } - - /* - * 显示用户的关注/粉丝列表 - * - * @param context - */ - public static void showFriends(Context context, int uid, int tabIdx) { - Bundle args = new Bundle(); - args.putInt(FriendsViewPagerFragment.BUNDLE_KEY_TABIDX, tabIdx); - args.putInt(FriendsFragment.BUNDLE_KEY_UID, uid); - showSimpleBack(context, SimpleBackPage.MY_FRIENDS, args); - } - /** * 显示留言对话页面 - * + * * @param context * @param friendid * @param friendid */ public static void showMessageDetail(Context context, int friendid, - String friendname) { - Bundle args = new Bundle(); - args.putInt(MessageDetailFragment.BUNDLE_KEY_FID, friendid); - args.putString(MessageDetailFragment.BUNDLE_KEY_FNAME, friendname); - showSimpleBack(context, SimpleBackPage.MESSAGE_DETAIL, args); + String friendname) { + User user = new User(); + user.setId(friendid); + user.setName(friendname); + UserSendMessageActivity.show(context, user); } /** * 显示设置界面 - * + * * @param context */ public static void showSetting(Context context) { showSimpleBack(context, SimpleBackPage.SETTING); } - /** - * 显示通知设置界面 - * - * @param context - */ - public static void showSettingNotification(Context context) { - showSimpleBack(context, SimpleBackPage.SETTING_NOTIFICATION); - } - /** * 显示关于界面 - * + * * @param context */ public static void showAboutOSC(Context context) { @@ -888,11 +584,9 @@ public class UIHelper { /** * 清除app缓存 - * - * @param activity */ - public static void clearAppCache(Activity activity) { - final Handler handler = new Handler() { + public static void clearAppCache(boolean showToast) { + final Handler handler = showToast ? new Handler() { @Override public void handleMessage(Message msg) { if (msg.what == 1) { @@ -901,8 +595,8 @@ public class UIHelper { AppContext.showToastShort("缓存清除失败"); } } - }; - new Thread() { + } : null; + AppOperator.runOnThread(new Runnable() { @Override public void run() { Message msg = new Message(); @@ -913,77 +607,14 @@ public class UIHelper { e.printStackTrace(); msg.what = -1; } - handler.sendMessage(msg); - } - }.start(); - } - - public static void openDownLoadService(Context context, String downurl, - String tilte) { - final ICallbackResult callback = new ICallbackResult() { - - @Override - public void OnBackResult(Object s) {} - }; - ServiceConnection conn = new ServiceConnection() { - - @Override - public void onServiceDisconnected(ComponentName name) {} - - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - DownloadBinder binder = (DownloadBinder) service; - binder.addCallback(callback); - binder.start(); - + if (handler != null) + handler.sendMessage(msg); } - }; - Intent intent = new Intent(context, DownloadService.class); - intent.putExtra(DownloadService.BUNDLE_KEY_DOWNLOAD_URL, downurl); - intent.putExtra(DownloadService.BUNDLE_KEY_TITLE, tilte); - context.startService(intent); - context.bindService(intent, conn, Context.BIND_AUTO_CREATE); - } - - /** - * 发送广播告知评论发生变化 - * - * @param context - * @param isBlog - * @param id - * @param catalog - * @param operation - * @param replyComment - */ - public static void sendBroadCastCommentChanged(Context context, - boolean isBlog, int id, int catalog, int operation, - Comment replyComment) { - Intent intent = new Intent(Constants.INTENT_ACTION_COMMENT_CHANGED); - Bundle args = new Bundle(); - args.putInt(Comment.BUNDLE_KEY_ID, id); - args.putInt(Comment.BUNDLE_KEY_CATALOG, catalog); - args.putBoolean(Comment.BUNDLE_KEY_BLOG, isBlog); - args.putInt(Comment.BUNDLE_KEY_OPERATION, operation); - args.putParcelable(Comment.BUNDLE_KEY_COMMENT, replyComment); - intent.putExtras(args); - context.sendBroadcast(intent); - } - - /** - * 显示活动地址地图信息 - * - * @param context - */ - public static void showEventLocation(Context context, String city, - String location) { - Intent intent = new Intent(context, EventLocationActivity.class); - intent.putExtra("city", city); - intent.putExtra("location", location); - context.startActivity(intent); + }); } public static void showCreateNewIssue(Context context, Team team, - TeamProject project, TeamIssueCatalog catalog) { + TeamProject project, TeamIssueCatalog catalog) { Bundle bundle = new Bundle(); bundle.putSerializable("team", team); if (project != null) { @@ -1000,16 +631,15 @@ public class UIHelper { /*** * 显示任务详情 - * - * @author 火蚁 2015-1-30 下午2:59:57 - * - * @return void + * * @param context * @param team * @param issue + * @return void + * @author 火蚁 2015-1-30 下午2:59:57 */ public static void showTeamIssueDetail(Context context, Team team, - TeamIssue issue, TeamIssueCatalog catalog) { + TeamIssue issue, TeamIssueCatalog catalog) { Intent intent = new Intent(context, DetailActivity.class); Bundle bundle = new Bundle(); bundle.putInt("teamid", team.getId()); @@ -1025,16 +655,15 @@ public class UIHelper { /** * 显示讨论贴详情 - * - * @author 火蚁 2015-2-2 下午6:37:53 - * - * @return void + * * @param context * @param team * @param discuss + * @return void + * @author 火蚁 2015-2-2 下午6:37:53 */ public static void showTeamDiscussDetail(Context context, Team team, - TeamDiscuss discuss) { + TeamDiscuss discuss) { Intent intent = new Intent(context, DetailActivity.class); Bundle bundle = new Bundle(); bundle.putInt("teamid", team.getId()); @@ -1047,7 +676,7 @@ public class UIHelper { /** * 显示周报详情 - * + * * @param context * @param data */ @@ -1060,7 +689,7 @@ public class UIHelper { } public static void showTeamMemberInfo(Context context, int teamId, - TeamMember teamMember) { + TeamMember teamMember) { Bundle bundle = new Bundle(); bundle.putSerializable(TeamMemberAdapter.TEAM_MEMBER_KEY, teamMember); bundle.putInt(TeamMemberAdapter.TEAM_ID_KEY, teamId); @@ -1069,16 +698,15 @@ public class UIHelper { /*** * 显示团队动态详情 - * - * @author 火蚁 2015-3-13 下午5:34:50 - * - * @return void + * * @param contex * @param teamId * @param active + * @return void + * @author 火蚁 2015-3-13 下午5:34:50 */ public static void showTeamActiveDetail(Context contex, int teamId, - TeamActive active) { + TeamActive active) { Intent intent = new Intent(contex, DetailActivity.class); Bundle bundle = new Bundle(); diff --git a/app/src/main/java/net/oschina/app/util/UpdateManager.java b/app/src/main/java/net/oschina/app/util/UpdateManager.java deleted file mode 100644 index c42f1ce63d55a13d74b39f36afcd15beabead34d..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/util/UpdateManager.java +++ /dev/null @@ -1,126 +0,0 @@ -package net.oschina.app.util; - -import android.app.Activity; -import android.app.ProgressDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.support.v7.app.AlertDialog; - -import com.loopj.android.http.AsyncHttpResponseHandler; - -import net.oschina.app.AppContext; -import net.oschina.app.api.remote.OSChinaApi; -import net.oschina.app.bean.Update; - -import cz.msebera.android.httpclient.Header; -import java.io.ByteArrayInputStream; - -/** - * 更新管理类 - * - * @author FireAnt(http://my.oschina.net/LittleDY) - * @version 创建时间:2014年11月18日 下午4:21:00 - */ - -public class UpdateManager { - - private Update mUpdate; - - private Context mContext; - - private boolean isShow = false; - - private ProgressDialog _waitDialog; - - private AsyncHttpResponseHandler mCheckUpdateHandle = new AsyncHttpResponseHandler() { - - @Override - public void onFailure(int arg0, Header[] arg1, byte[] arg2, - Throwable arg3) { - hideCheckDialog(); - if (isShow) { - showFaileDialog(); - } - } - - @Override - public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { - hideCheckDialog(); - mUpdate = XmlUtils.toBean(Update.class, - new ByteArrayInputStream(arg2)); - - onFinshCheck(); - } - }; - - public UpdateManager(Context context, boolean isShow) { - this.mContext = context; - this.isShow = isShow; - } - - public boolean haveNew() { - if (this.mUpdate == null) { - return false; - } - boolean haveNew = false; - int curVersionCode = TDevice.getVersionCode(AppContext - .getInstance().getPackageName()); - if (curVersionCode < mUpdate.getUpdate().getAndroid() - .getVersionCode()) { - haveNew = true; - } - return haveNew; - } - - public void checkUpdate() { - if (isShow) { - showCheckDialog(); - } - OSChinaApi.checkUpdate(mCheckUpdateHandle); - } - - private void onFinshCheck() { - if (haveNew()) { - showUpdateInfo(); - } else { - if (isShow) { - showLatestDialog(); - } - } - } - - private void showCheckDialog() { - if (_waitDialog == null) { - _waitDialog = DialogHelp.getWaitDialog((Activity) mContext, "正在获取新版本信息..."); - } - _waitDialog.show(); - } - - private void hideCheckDialog() { - if (_waitDialog != null) { - _waitDialog.dismiss(); - } - } - - private void showUpdateInfo() { - if (mUpdate == null) { - return; - } - AlertDialog.Builder dialog = DialogHelp.getConfirmDialog(mContext, mUpdate.getUpdate().getAndroid().getUpdateLog(), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - UIHelper.openDownLoadService(mContext, mUpdate.getUpdate().getAndroid().getDownloadUrl(), mUpdate.getUpdate().getAndroid().getVersionName()); - } - }); - dialog.setTitle("发现新版本"); - dialog.show(); - } - - private void showLatestDialog() { - DialogHelp.getMessageDialog(mContext, "已经是新版本了").show(); - } - - private void showFaileDialog() { - DialogHelp.getMessageDialog(mContext, "网络异常,无法获取新版本信息").show(); - } -} diff --git a/app/src/main/java/net/oschina/app/util/ZipUtils.java b/app/src/main/java/net/oschina/app/util/ZipUtils.java deleted file mode 100644 index e704717cae7b210cb0fb403282506f2e2130b256..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/util/ZipUtils.java +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Copyright (c) 2014,KJFrameForAndroid Open Source Project,张涛. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package net.oschina.app.util; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Enumeration; -import java.util.zip.ZipEntry; -import java.util.zip.ZipException; -import java.util.zip.ZipFile; -import java.util.zip.ZipOutputStream; - -/** - * ZIP文件工具类 - * - * @author kymjs(kymjs123@gmail.com) - */ -public class ZipUtils { - private static final int BUFF_SIZE = 1024 * 1024; // 1M Byte - - /** - * 批量压缩文件(夹) - * - * @param resFileList - * 要压缩的文件(夹)列表 - * @param zipFile - * 生成的压缩文件 - * @throws IOException - * 当压缩过程出错时抛出 - */ - public static void zipFiles(Collection resFileList, File zipFile) - throws IOException { - ZipOutputStream zipout = new ZipOutputStream(new BufferedOutputStream( - new FileOutputStream(zipFile), BUFF_SIZE)); - for (File resFile : resFileList) { - zipFile(resFile, zipout, ""); - } - zipout.close(); - } - - /** - * 批量压缩文件(夹) - * - * @param resFileList - * 要压缩的文件(夹)列表 - * @param zipFile - * 生成的压缩文件 - * @param comment - * 压缩文件的注释 - * @throws IOException - * 当压缩过程出错时抛出 - */ - public static void zipFiles(Collection resFileList, File zipFile, - String comment) throws IOException { - ZipOutputStream zipout = new ZipOutputStream(new BufferedOutputStream( - new FileOutputStream(zipFile), BUFF_SIZE)); - for (File resFile : resFileList) { - zipFile(resFile, zipout, ""); - } - zipout.setComment(comment); - zipout.close(); - } - - /** - * 解压缩一个文件 - * - * @param zipFile - * 压缩文件 - * @param folderPath - * 文件解压到指定目标路径 - * @throws IOException - * 当解压缩过程出错时抛出 - */ - public static void upZipFile(File zipFile, String folderPath) - throws ZipException, IOException { - File desDir = new File(folderPath); - if (!desDir.exists()) { - desDir.mkdirs(); - } - ZipFile zf = new ZipFile(zipFile); - for (Enumeration entries = zf.entries(); entries.hasMoreElements();) { - ZipEntry entry = ((ZipEntry) entries.nextElement()); - InputStream in = zf.getInputStream(entry); - String str = folderPath + File.separator + entry.getName(); - str = new String(str.getBytes("8859_1"), "GB2312"); - File desFile = new File(str); - if (!desFile.exists()) { - File fileParentDir = desFile.getParentFile(); - if (!fileParentDir.exists()) { - fileParentDir.mkdirs(); - } - desFile.createNewFile(); - } - OutputStream out = new FileOutputStream(desFile); - byte buffer[] = new byte[BUFF_SIZE]; - int realLength; - while ((realLength = in.read(buffer)) > 0) { - out.write(buffer, 0, realLength); - } - in.close(); - out.close(); - } - } - - /** - * 解压文件名包含传入文字的文件 - * - * @param zipFile - * 压缩文件 - * @param folderPath - * 目标文件夹 - * @param nameContains - * 传入的文件匹配名 - * @throws ZipException - * 压缩格式有误时抛出 - * @throws IOException - * IO错误时抛出 - */ - public static ArrayList upZipSelectedFile(File zipFile, - String folderPath, String nameContains) throws ZipException, - IOException { - ArrayList fileList = new ArrayList(); - - File desDir = new File(folderPath); - if (!desDir.exists()) { - desDir.mkdir(); - } - - ZipFile zf = new ZipFile(zipFile); - for (Enumeration entries = zf.entries(); entries.hasMoreElements();) { - ZipEntry entry = ((ZipEntry) entries.nextElement()); - if (entry.getName().contains(nameContains)) { - InputStream in = zf.getInputStream(entry); - String str = folderPath + File.separator + entry.getName(); - str = new String(str.getBytes("8859_1"), "GB2312"); - // str.getBytes("GB2312"),"8859_1" 输出 - // str.getBytes("8859_1"),"GB2312" 输入 - File desFile = new File(str); - if (!desFile.exists()) { - File fileParentDir = desFile.getParentFile(); - if (!fileParentDir.exists()) { - fileParentDir.mkdirs(); - } - desFile.createNewFile(); - } - OutputStream out = new FileOutputStream(desFile); - byte buffer[] = new byte[BUFF_SIZE]; - int realLength; - while ((realLength = in.read(buffer)) > 0) { - out.write(buffer, 0, realLength); - } - in.close(); - out.close(); - fileList.add(desFile); - } - } - return fileList; - } - - /** - * 获得压缩文件内文件列表 - * - * @param zipFile - * 压缩文件 - * @return 压缩文件内文件名称 - * @throws ZipException - * 压缩文件格式有误时抛出 - * @throws IOException - * 当解压缩过程出错时抛出 - */ - public static ArrayList getEntriesNames(File zipFile) - throws ZipException, IOException { - ArrayList entryNames = new ArrayList(); - Enumeration entries = getEntriesEnumeration(zipFile); - while (entries.hasMoreElements()) { - ZipEntry entry = ((ZipEntry) entries.nextElement()); - entryNames.add(new String(getEntryName(entry).getBytes("GB2312"), - "8859_1")); - } - return entryNames; - } - - /** - * 获得压缩文件内压缩文件对象以取得其属性 - * - * @param zipFile - * 压缩文件 - * @return 返回一个压缩文件列表 - * @throws ZipException - * 压缩文件格式有误时抛出 - * @throws IOException - * IO操作有误时抛出 - */ - public static Enumeration getEntriesEnumeration(File zipFile) - throws ZipException, IOException { - ZipFile zf = new ZipFile(zipFile); - return zf.entries(); - - } - - /** - * 取得压缩文件对象的注释 - * - * @param entry - * 压缩文件对象 - * @return 压缩文件对象的注释 - * @throws UnsupportedEncodingException - */ - public static String getEntryComment(ZipEntry entry) - throws UnsupportedEncodingException { - return new String(entry.getComment().getBytes("GB2312"), "8859_1"); - } - - /** - * 取得压缩文件对象的名称 - * - * @param entry - * 压缩文件对象 - * @return 压缩文件对象的名称 - * @throws UnsupportedEncodingException - */ - public static String getEntryName(ZipEntry entry) - throws UnsupportedEncodingException { - return new String(entry.getName().getBytes("GB2312"), "8859_1"); - } - - /** - * 压缩文件 - * - * @param resFile - * 需要压缩的文件(夹) - * @param zipout - * 压缩的目的文件 - * @param rootpath - * 压缩的文件路径 - * @throws FileNotFoundException - * 找不到文件时抛出 - * @throws IOException - * 当压缩过程出错时抛出 - */ - private static void zipFile(File resFile, ZipOutputStream zipout, - String rootpath) throws FileNotFoundException, IOException { - rootpath = rootpath - + (rootpath.trim().length() == 0 ? "" : File.separator) - + resFile.getName(); - rootpath = new String(rootpath.getBytes("8859_1"), "GB2312"); - if (resFile.isDirectory()) { - File[] fileList = resFile.listFiles(); - for (File file : fileList) { - zipFile(file, zipout, rootpath); - } - } else { - byte buffer[] = new byte[BUFF_SIZE]; - BufferedInputStream in = new BufferedInputStream( - new FileInputStream(resFile), BUFF_SIZE); - zipout.putNextEntry(new ZipEntry(rootpath)); - int realLength; - while ((realLength = in.read(buffer)) != -1) { - zipout.write(buffer, 0, realLength); - } - in.close(); - zipout.flush(); - zipout.closeEntry(); - } - } -} diff --git a/app/src/main/java/net/oschina/app/viewpagerfragment/BlogViewPagerFragment.java b/app/src/main/java/net/oschina/app/viewpagerfragment/BlogViewPagerFragment.java deleted file mode 100644 index 409c8c73a6048406e164fe5f81e77f0e1f3c938d..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/viewpagerfragment/BlogViewPagerFragment.java +++ /dev/null @@ -1,52 +0,0 @@ -package net.oschina.app.viewpagerfragment; - -import net.oschina.app.R; -import net.oschina.app.adapter.ViewPageFragmentAdapter; -import net.oschina.app.base.BaseViewPagerFragment; -import net.oschina.app.bean.BlogList; -import net.oschina.app.fragment.BlogFragment; -import android.os.Bundle; -import android.view.View; - -/** - * 博客区ViewPager - * - * @author kymjs(kymjs123@gmail.com) - */ -public class BlogViewPagerFragment extends BaseViewPagerFragment { - - @Override - public void initView(View view) {} - - @Override - public void initData() {} - - @Override - public void onClick(View v) {} - - @Override - protected void onSetupTabAdapter(ViewPageFragmentAdapter adapter) { - String[] title = getResources().getStringArray( - R.array.blogs_viewpage_arrays); - // 最新博客 - adapter.addTab(title[0], "latest_blog", BlogFragment.class, - getBundle(BlogList.CATALOG_LATEST)); - // 推荐博客 - adapter.addTab(title[1], "recommend_blog", BlogFragment.class, - getBundle(BlogList.CATALOG_RECOMMEND)); - } - - /** - * 基类会根据不同的catalog展示相应的数据 - * - * @param catalog - * 要显示的数据类别 - * @return - */ - private Bundle getBundle(String catalog) { - Bundle bundle = new Bundle(); - bundle.putString(BlogFragment.BUNDLE_BLOG_TYPE, catalog); - return bundle; - } - -} diff --git a/app/src/main/java/net/oschina/app/viewpagerfragment/EventViewPagerFragment.java b/app/src/main/java/net/oschina/app/viewpagerfragment/EventViewPagerFragment.java index 7b0bf565583382346a84d6df64be0e8bf08fa909..8d4829b80b02cb72857b3e21f408f80b14b49c59 100644 --- a/app/src/main/java/net/oschina/app/viewpagerfragment/EventViewPagerFragment.java +++ b/app/src/main/java/net/oschina/app/viewpagerfragment/EventViewPagerFragment.java @@ -1,47 +1,71 @@ package net.oschina.app.viewpagerfragment; +import android.content.Context; +import android.os.Bundle; +import android.view.View; +import android.widget.FrameLayout; + import net.oschina.app.R; import net.oschina.app.adapter.ViewPageFragmentAdapter; import net.oschina.app.base.BaseViewPagerFragment; import net.oschina.app.bean.EventList; import net.oschina.app.fragment.EventFragment; -import android.os.Bundle; -import android.view.View; +import net.oschina.app.ui.SimpleBackActivity; -/** +/** * 活动viewpager页面 - * + * * @author FireAnt(http://my.oschina.net/LittleDY) - * @version 创建时间:2014年12月24日 下午4:46:04 - * + * @version 创建时间:2014年12月24日 下午4:46:04 */ public class EventViewPagerFragment extends BaseViewPagerFragment { - @Override - protected void onSetupTabAdapter(ViewPageFragmentAdapter adapter) { - String[] title = getResources().getStringArray(R.array.events); - adapter.addTab(title[0], "new_event", EventFragment.class, getBundle(EventList.EVENT_LIST_TYPE_NEW_EVENT)); - adapter.addTab(title[1], "my_event", EventFragment.class, getBundle(EventList.EVENT_LIST_TYPE_MY_EVENT)); - } - - private Bundle getBundle(int event_type) { - Bundle bundle = new Bundle(); - bundle.putInt(EventFragment.BUNDLE_KEY_EVENT_TYPE, event_type); - return bundle; - } - - @Override - public void onClick(View v) { - - } - - @Override - public void initView(View view) { - - } - - @Override - public void initData() { - - } + private int position = 0; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + Bundle bundle = getArguments(); + position = bundle.getInt(SimpleBackActivity.BUNDLE_KEY_ARGS, 0); + } + + @Override + protected void onSetupTabAdapter(ViewPageFragmentAdapter adapter) { + + FrameLayout generalActionBar = (FrameLayout) mRoot.findViewById(R.id.general_actionbar); + generalActionBar.setVisibility(View.GONE); + + String[] title = getResources().getStringArray(R.array.events); + if (position == 0) { + adapter.addTab(title[0], "new_event", EventFragment.class, getBundle(EventList.EVENT_LIST_TYPE_NEW_EVENT)); + adapter.addTab(title[1], "my_event", EventFragment.class, getBundle(EventList.EVENT_LIST_TYPE_MY_EVENT)); + mTabStrip.setVisibility(View.VISIBLE); + } else { + adapter.addTab(title[1], "my_event", EventFragment.class, getBundle(EventList.EVENT_LIST_TYPE_MY_EVENT)); + mTabStrip.setVisibility(View.GONE); + } + mViewPager.setCurrentItem(position, true); + } + + private Bundle getBundle(int event_type) { + + Bundle bundle = new Bundle(); + bundle.putInt(EventFragment.BUNDLE_KEY_EVENT_TYPE, event_type); + return bundle; + } + + @Override + public void onClick(View v) { + + } + + @Override + public void initView(View view) { + + } + + @Override + public void initData() { + + } } diff --git a/app/src/main/java/net/oschina/app/viewpagerfragment/FriendsViewPagerFragment.java b/app/src/main/java/net/oschina/app/viewpagerfragment/FriendsViewPagerFragment.java deleted file mode 100644 index 403edc98b3fcf832e5f46c1f06b4ffb687657c07..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/viewpagerfragment/FriendsViewPagerFragment.java +++ /dev/null @@ -1,67 +0,0 @@ -package net.oschina.app.viewpagerfragment; - -import net.oschina.app.R; -import net.oschina.app.adapter.ViewPageFragmentAdapter; -import net.oschina.app.base.BaseListFragment; -import net.oschina.app.base.BaseViewPagerFragment; -import net.oschina.app.bean.FriendsList; -import net.oschina.app.fragment.FriendsFragment; -import android.os.Bundle; -import android.view.View; - -/** - * 关注、粉丝viewpager页面 - * @author FireAnt(http://my.oschina.net/LittleDY) - * @created 2014年9月25日 下午2:21:52 - * - */ -public class FriendsViewPagerFragment extends BaseViewPagerFragment { - - public static final String BUNDLE_KEY_TABIDX = "BUNDLE_KEY_TABIDX"; - - private int mInitTabIdx; - - private int mUid; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - Bundle args = getArguments(); - mInitTabIdx = args.getInt(BUNDLE_KEY_TABIDX, 0); - mUid = args.getInt(FriendsFragment.BUNDLE_KEY_UID, 0); - } - - @Override - protected void onSetupTabAdapter(ViewPageFragmentAdapter adapter) { - String[] title = getResources().getStringArray(R.array.friends_viewpage_arrays); - adapter.addTab(title[0], "follower", FriendsFragment.class, getBundle(FriendsList.TYPE_FOLLOWER)); - adapter.addTab(title[1], "following", FriendsFragment.class, getBundle(FriendsList.TYPE_FANS)); - - mViewPager.setCurrentItem(mInitTabIdx); - } - - private Bundle getBundle(int catalog) { - Bundle bundle = new Bundle(); - bundle.putInt(BaseListFragment.BUNDLE_KEY_CATALOG, catalog); - bundle.putInt(FriendsFragment.BUNDLE_KEY_UID, mUid); - return bundle; - } - - @Override - public void onClick(View v) { - // TODO Auto-generated method stub - - } - - @Override - public void initView(View view) { - // TODO Auto-generated method stub - - } - - @Override - public void initData() { - // TODO Auto-generated method stub - - } -} diff --git a/app/src/main/java/net/oschina/app/viewpagerfragment/NewsViewPagerFragment.java b/app/src/main/java/net/oschina/app/viewpagerfragment/NewsViewPagerFragment.java deleted file mode 100644 index 4372e8a77773c000cf3043a5535c92b4bdad5310..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/viewpagerfragment/NewsViewPagerFragment.java +++ /dev/null @@ -1,93 +0,0 @@ -package net.oschina.app.viewpagerfragment; - -import net.oschina.app.R; -import net.oschina.app.adapter.ViewPageFragmentAdapter; -import net.oschina.app.base.BaseListFragment; -import net.oschina.app.base.BaseViewPagerFragment; -import net.oschina.app.bean.BlogList; -import net.oschina.app.bean.NewsList; -import net.oschina.app.fragment.BlogFragment; -import net.oschina.app.fragment.NewsFragment; -import net.oschina.app.interf.OnTabReselectListener; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.view.View; - -/** - * 资讯viewpager页面 - * - * @author FireAnt(http://my.oschina.net/LittleDY) - * @created 2014年9月25日 下午2:21:52 - * - */ -public class NewsViewPagerFragment extends BaseViewPagerFragment implements - OnTabReselectListener { - - @Override - protected void onSetupTabAdapter(ViewPageFragmentAdapter adapter) { - String[] title = getResources().getStringArray( - R.array.news_viewpage_arrays); - adapter.addTab(title[0], "news", NewsFragment.class, - getBundle(NewsList.CATALOG_ALL)); - adapter.addTab(title[1], "news_week", NewsFragment.class, - getBundle(NewsList.CATALOG_WEEK)); - adapter.addTab(title[2], "latest_blog", BlogFragment.class, - getBundle(BlogList.CATALOG_LATEST)); - adapter.addTab(title[3], "recommend_blog", BlogFragment.class, - getBundle(BlogList.CATALOG_RECOMMEND)); - } - - private Bundle getBundle(int newType) { - Bundle bundle = new Bundle(); - bundle.putInt(BaseListFragment.BUNDLE_KEY_CATALOG, newType); - return bundle; - } - - @Override - protected void setScreenPageLimit() { - mViewPager.setOffscreenPageLimit(3); - } - - /** - * 基类会根据不同的catalog展示相应的数据 - * - * @param catalog - * 要显示的数据类别 - * @return - */ - private Bundle getBundle(String catalog) { - Bundle bundle = new Bundle(); - bundle.putString(BlogFragment.BUNDLE_BLOG_TYPE, catalog); - return bundle; - } - - @Override - public void onClick(View v) { - - } - - @Override - public void initView(View view) { - - } - - @Override - public void initData() { - - } - - @Override - public void onTabReselect() { - try { - int currentIndex = mViewPager.getCurrentItem(); - Fragment currentFragment = getChildFragmentManager().getFragments() - .get(currentIndex); - if (currentFragment != null - && currentFragment instanceof OnTabReselectListener) { - OnTabReselectListener listener = (OnTabReselectListener) currentFragment; - listener.onTabReselect(); - } - } catch (NullPointerException e) { - } - } -} diff --git a/app/src/main/java/net/oschina/app/viewpagerfragment/NoticeViewPagerFragment.java b/app/src/main/java/net/oschina/app/viewpagerfragment/NoticeViewPagerFragment.java deleted file mode 100644 index 7ab873ca9b4f0d5d028511b78b825082e6090a52..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/viewpagerfragment/NoticeViewPagerFragment.java +++ /dev/null @@ -1,278 +0,0 @@ -package net.oschina.app.viewpagerfragment; - -import net.oschina.app.AppContext; -import net.oschina.app.R; -import net.oschina.app.adapter.ViewPageFragmentAdapter; -import net.oschina.app.base.BaseListFragment; -import net.oschina.app.base.BaseViewPagerFragment; -import net.oschina.app.bean.ActiveList; -import net.oschina.app.bean.Constants; -import net.oschina.app.bean.FriendsList; -import net.oschina.app.bean.Notice; -import net.oschina.app.bean.TweetsList; -import net.oschina.app.fragment.ActiveFragment; -import net.oschina.app.fragment.FriendsFragment; -import net.oschina.app.fragment.MessageFragment; -import net.oschina.app.fragment.TweetsFragment; -import net.oschina.app.fragment.TweetsLikesFragment; -import net.oschina.app.ui.MainActivity; -import net.oschina.app.widget.BadgeView; -import net.oschina.app.widget.PagerSlidingTabStrip.OnPagerChangeLis; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Bundle; -import android.util.TypedValue; -import android.view.Gravity; -import android.view.View; - -/** - * 消息中心页面 - * - * @author FireAnt(http://my.oschina.net/LittleDY) - * @author kymjs (https://github.com/kymjs) - * @created 2014年9月25日 下午2:21:52 - * - */ -public class NoticeViewPagerFragment extends BaseViewPagerFragment { - - public BadgeView mBvAtMe, mBvComment, mBvMsg, mBvFans, mBvLike; - public static int sCurrentPage = 0; - public static int[] sShowCount = new int[] { 0, 0, 0, 0, 0}; // 当前界面显示了多少次 - private BroadcastReceiver mNoticeReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - setNoticeTip(); - changePagers(); - } - }; - - /** - * 界面每次显示,去重置tip的显示 - */ - @Override - public void onResume() { - super.onResume(); - setNoticeTip(); - changePagers(); - mViewPager.setOffscreenPageLimit(2); - } - - /** - * 设置tip - */ - private void setNoticeTip() { - Notice notice = MainActivity.mNotice; - if (notice != null) { - changeTip(mBvAtMe, notice.getAtmeCount());// @我 - changeTip(mBvComment, notice.getReviewCount());// 评论 - changeTip(mBvMsg, notice.getMsgCount());// 私信 - changeTip(mBvFans, notice.getNewFansCount());// 新粉丝 - changeTip(mBvLike, notice.getNewLikeCount());// 点赞数 - } else { - switch (mViewPager.getCurrentItem()) { - case 0: - changeTip(mBvAtMe, -1); - break; - case 1: - changeTip(mBvComment, -1); - break; - case 2: - changeTip(mBvMsg, -1); - break; - case 3: - changeTip(mBvFans, -1); - break; - case 4: - changeTip(mBvLike, -1); - break; - } - } - } - - /** - * 判断指定控件是否应该显示tip红点 - * - * @author kymjs - */ - private void changeTip(BadgeView view, int count) { - if (count > 0) { - view.setText(count + ""); - view.show(); - } else { - view.hide(); - } - } - - /** - * 当前tip是否在显示 - * - * @param which - * 哪个界面的tip - * @return - */ - private boolean tipIsShow(int which) { - switch (which) { - case 0: - return mBvAtMe.isShown(); - case 1: - return mBvComment.isShown(); - case 2: - return mBvMsg.isShown(); - case 3: - return mBvFans.isShown(); - case 4: - return mBvLike.isShown(); - default: - return false; - } - } - - /** - * 首次进入,切换到有tip的page - */ - private void changePagers() { - Notice notice = MainActivity.mNotice; - if (notice == null) { - return; - } - if (notice.getAtmeCount() != 0) { - mViewPager.setCurrentItem(0); - sCurrentPage = 0; - refreshPage(0); - sShowCount[0] = 1; - } else if (notice.getReviewCount() != 0) { - mViewPager.setCurrentItem(1); - sCurrentPage = 1; - refreshPage(1); - sShowCount[1] = 1; - } else if (notice.getMsgCount() != 0) { - mViewPager.setCurrentItem(2); - sCurrentPage = 2; - refreshPage(2); - sShowCount[2] = 1; - } else if (notice.getNewFansCount() != 0) { - mViewPager.setCurrentItem(3); - sCurrentPage = 3; - refreshPage(3); - sShowCount[3] = 1; - } else if (notice.getNewLikeCount() != 0) { - mViewPager.setCurrentItem(4); - sCurrentPage = 4; - refreshPage(4); - sShowCount[4] = 1; - } - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - // 注册接收者接受tip广播 - IntentFilter filter = new IntentFilter(Constants.INTENT_ACTION_NOTICE); - getActivity().registerReceiver(mNoticeReceiver, filter); - - mBvAtMe = new BadgeView(getActivity(), mTabStrip.getBadgeView(0)); - mBvAtMe.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10); - mBvAtMe.setBadgePosition(BadgeView.POSITION_CENTER); - mBvAtMe.setGravity(Gravity.CENTER); - mBvAtMe.setBackgroundResource(R.drawable.notification_bg); - - mBvComment = new BadgeView(getActivity(), mTabStrip.getBadgeView(1)); - mBvComment.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10); - mBvComment.setBadgePosition(BadgeView.POSITION_CENTER); - mBvComment.setGravity(Gravity.CENTER); - mBvComment.setBackgroundResource(R.drawable.notification_bg); - - mBvMsg = new BadgeView(getActivity(), mTabStrip.getBadgeView(2)); - mBvMsg.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10); - mBvMsg.setBadgePosition(BadgeView.POSITION_CENTER); - mBvMsg.setGravity(Gravity.CENTER); - mBvMsg.setBackgroundResource(R.drawable.notification_bg); - - mBvFans = new BadgeView(getActivity(), mTabStrip.getBadgeView(3)); - mBvFans.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10); - mBvFans.setBadgePosition(BadgeView.POSITION_CENTER); - mBvFans.setGravity(Gravity.CENTER); - mBvFans.setBackgroundResource(R.drawable.notification_bg); - - mBvLike = new BadgeView(getActivity(), mTabStrip.getBadgeView(4)); - mBvLike.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10); - mBvLike.setBadgePosition(BadgeView.POSITION_CENTER); - mBvLike.setGravity(Gravity.CENTER); - mBvLike.setBackgroundResource(R.drawable.notification_bg); - - mTabStrip.getBadgeView(0).setVisibility(View.GONE); - mTabStrip.getBadgeView(1).setVisibility(View.VISIBLE); - mTabStrip.getBadgeView(2).setVisibility(View.VISIBLE); - mTabStrip.getBadgeView(3).setVisibility(View.VISIBLE); - mTabStrip.getBadgeView(4).setVisibility(View.VISIBLE); - initData(); - initView(view); - } - - @Override - protected void setScreenPageLimit() { - mViewPager.setOffscreenPageLimit(3); - } - - @Override - public void onDestroy() { - super.onDestroy(); - getActivity().unregisterReceiver(mNoticeReceiver); - mNoticeReceiver = null; - } - - @Override - protected void onSetupTabAdapter(ViewPageFragmentAdapter adapter) { - String[] title = getResources().getStringArray( - R.array.mymes_viewpage_arrays); - adapter.addTab(title[0], "active_me", ActiveFragment.class, - getBundle(ActiveList.CATALOG_ATME)); - adapter.addTab(title[1], "active_comment", ActiveFragment.class, - getBundle(ActiveList.CATALOG_COMMENT)); - adapter.addTab(title[2], "active_mes", MessageFragment.class, null); - Bundle bundle = getBundle(FriendsList.TYPE_FANS); - bundle.putInt(FriendsFragment.BUNDLE_KEY_UID, AppContext.getInstance() - .getLoginUid()); - adapter.addTab(title[3], "active_fans", FriendsFragment.class, bundle); - adapter.addTab(title[4], "my_tweet", TweetsLikesFragment.class, null); - } - - private Bundle getBundle(int catalog) { - Bundle bundle = new Bundle(); - bundle.putInt(BaseListFragment.BUNDLE_KEY_CATALOG, catalog); - return bundle; - } - - @Override - public void onClick(View v) {} - - @Override - public void initView(View view) { - changePagers(); - mViewPager.setOffscreenPageLimit(3); - mTabStrip.setOnPagerChange(new OnPagerChangeLis() { - @Override - public void onChanged(int page) { - refreshPage(page); - sShowCount[page]++; - sCurrentPage = page; - } - }); - } - - private void refreshPage(int index) { - if (tipIsShow(index)) { - try { - ((BaseListFragment) getChildFragmentManager().getFragments() - .get(index)).onRefresh(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - - @Override - public void initData() {} -} diff --git a/app/src/main/java/net/oschina/app/viewpagerfragment/OpenSoftwareFragment.java b/app/src/main/java/net/oschina/app/viewpagerfragment/OpenSoftwareFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..6978ed6f59d69335a05099d1d6048727bba37b68 --- /dev/null +++ b/app/src/main/java/net/oschina/app/viewpagerfragment/OpenSoftwareFragment.java @@ -0,0 +1,68 @@ +package net.oschina.app.viewpagerfragment; + +import android.os.Bundle; +import android.view.View; +import android.widget.FrameLayout; + +import net.oschina.app.R; +import net.oschina.app.adapter.ViewPageFragmentAdapter; +import net.oschina.app.base.BaseFragment; +import net.oschina.app.base.BaseViewPagerFragment; +import net.oschina.app.bean.SoftwareList; +import net.oschina.app.fragment.SoftwareCatalogListFragment; +import net.oschina.app.fragment.SoftwareListFragment; + +public class OpenSoftwareFragment extends BaseViewPagerFragment { + + @Override + protected void onSetupTabAdapter(ViewPageFragmentAdapter adapter) { + + FrameLayout generalActionBar = (FrameLayout) mRoot.findViewById(R.id.general_actionbar); + generalActionBar.setVisibility(View.GONE); + + String[] title = getResources().getStringArray( + R.array.opensourcesoftware); + adapter.addTab(title[0], "software_catalog", + SoftwareCatalogListFragment.class, null); + adapter.addTab(title[1], "software_recommend", + SoftwareListFragment.class, + getBundle(SoftwareList.CATALOG_RECOMMEND)); + adapter.addTab(title[2], "software_latest", SoftwareListFragment.class, + getBundle(SoftwareList.CATALOG_TIME)); + adapter.addTab(title[3], "software_hot", SoftwareListFragment.class, + getBundle(SoftwareList.CATALOG_VIEW)); + adapter.addTab(title[4], "software_china", SoftwareListFragment.class, + getBundle(SoftwareList.CATALOG_LIST_CN)); + } + + private Bundle getBundle(String catalog) { + Bundle bundle = new Bundle(); + bundle.putString(SoftwareListFragment.BUNDLE_SOFTWARE, catalog); + return bundle; + } + + @Override + public void onClick(View v) { + + } + + @Override + public void initView(View view) { + + } + + @Override + public void initData() { + + } + + @Override + public boolean onBackPressed() { + BaseFragment fragment = (BaseFragment) mTabsAdapter.getItem(mViewPager + .getCurrentItem()); + if (fragment instanceof SoftwareCatalogListFragment) { + return fragment.onBackPressed(); + } + return super.onBackPressed(); + } +} \ No newline at end of file diff --git a/app/src/main/java/net/oschina/app/viewpagerfragment/OpensourceSoftwareFragment.java b/app/src/main/java/net/oschina/app/viewpagerfragment/OpensourceSoftwareFragment.java deleted file mode 100644 index c4564bdc4ea1dcce773e21276e7d9f1bfb0c9760..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/viewpagerfragment/OpensourceSoftwareFragment.java +++ /dev/null @@ -1,66 +0,0 @@ -package net.oschina.app.viewpagerfragment; - -import net.oschina.app.R; -import net.oschina.app.adapter.ViewPageFragmentAdapter; -import net.oschina.app.base.BaseFragment; -import net.oschina.app.base.BaseViewPagerFragment; -import net.oschina.app.bean.SoftwareList; -import net.oschina.app.fragment.SoftwareCatalogListFragment; -import net.oschina.app.fragment.SoftwareListFragment; -import android.os.Bundle; -import android.view.View; - -public class OpensourceSoftwareFragment extends BaseViewPagerFragment { - - public static OpensourceSoftwareFragment newInstance() { - return new OpensourceSoftwareFragment(); - } - - @Override - protected void onSetupTabAdapter(ViewPageFragmentAdapter adapter) { - String[] title = getResources().getStringArray( - R.array.opensourcesoftware); - adapter.addTab(title[0], "software_catalog", - SoftwareCatalogListFragment.class, null); - adapter.addTab(title[1], "software_recommend", - SoftwareListFragment.class, - getBundle(SoftwareList.CATALOG_RECOMMEND)); - adapter.addTab(title[2], "software_latest", SoftwareListFragment.class, - getBundle(SoftwareList.CATALOG_TIME)); - adapter.addTab(title[3], "software_hot", SoftwareListFragment.class, - getBundle(SoftwareList.CATALOG_VIEW)); - adapter.addTab(title[4], "software_china", SoftwareListFragment.class, - getBundle(SoftwareList.CATALOG_LIST_CN)); - } - - private Bundle getBundle(String catalog) { - Bundle bundle = new Bundle(); - bundle.putString(SoftwareListFragment.BUNDLE_SOFTWARE, catalog); - return bundle; - } - - @Override - public void onClick(View v) { - - } - - @Override - public void initView(View view) { - - } - - @Override - public void initData() { - - } - - @Override - public boolean onBackPressed() { - BaseFragment fragment = (BaseFragment) mTabsAdapter.getItem(mViewPager - .getCurrentItem()); - if (fragment instanceof SoftwareCatalogListFragment) { - return fragment.onBackPressed(); - } - return super.onBackPressed(); - } -} \ No newline at end of file diff --git a/app/src/main/java/net/oschina/app/viewpagerfragment/QuestViewPagerFragment.java b/app/src/main/java/net/oschina/app/viewpagerfragment/QuestViewPagerFragment.java deleted file mode 100644 index 54a7c8ed612d25fc1d249e9aa7d3b2499ea680ce..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/viewpagerfragment/QuestViewPagerFragment.java +++ /dev/null @@ -1,53 +0,0 @@ -package net.oschina.app.viewpagerfragment; - -import net.oschina.app.R; -import net.oschina.app.adapter.ViewPageFragmentAdapter; -import net.oschina.app.base.BaseListFragment; -import net.oschina.app.base.BaseViewPagerFragment; -import net.oschina.app.bean.Post; -import net.oschina.app.fragment.PostsFragment; -import android.os.Bundle; -import android.view.View; - -/** - * - * @author FireAnt(http://my.oschina.net/LittleDY) - * @created 2014年9月25日 下午2:21:52 - * - */ -public class QuestViewPagerFragment extends BaseViewPagerFragment { - - @Override - protected void onSetupTabAdapter(ViewPageFragmentAdapter adapter) { - String[] title = getResources().getStringArray(R.array.quests_viewpage_arrays); - adapter.addTab(title[0], "quest_ask", PostsFragment.class, getBundle(Post.CATALOG_ASK)); - adapter.addTab(title[1], "quest_share", PostsFragment.class, getBundle(Post.CATALOG_SHARE)); - adapter.addTab(title[2], "quest_multiple", PostsFragment.class, getBundle(Post.CATALOG_OTHER)); - adapter.addTab(title[3], "quest_occupation", PostsFragment.class, getBundle(Post.CATALOG_JOB)); - adapter.addTab(title[4], "quest_station", PostsFragment.class, getBundle(Post.CATALOG_SITE)); - } - - private Bundle getBundle(int catalog) { - Bundle bundle = new Bundle(); - bundle.putInt(BaseListFragment.BUNDLE_KEY_CATALOG, catalog); - return bundle; - } - - @Override - public void onClick(View v) { - // TODO Auto-generated method stub - - } - - @Override - public void initView(View view) { - // TODO Auto-generated method stub - - } - - @Override - public void initData() { - // TODO Auto-generated method stub - - } -} diff --git a/app/src/main/java/net/oschina/app/viewpagerfragment/SearchViewPageFragment.java b/app/src/main/java/net/oschina/app/viewpagerfragment/SearchViewPageFragment.java deleted file mode 100644 index 0a4a5ec70e62e481858bfdd740fa5d02d560537e..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/viewpagerfragment/SearchViewPageFragment.java +++ /dev/null @@ -1,121 +0,0 @@ -package net.oschina.app.viewpagerfragment; - -import net.oschina.app.R; -import net.oschina.app.adapter.ViewPageFragmentAdapter; -import net.oschina.app.base.BaseListFragment; -import net.oschina.app.base.BaseViewPagerFragment; -import net.oschina.app.bean.SearchList; -import net.oschina.app.fragment.SearchFragment; -import net.oschina.app.util.TDevice; -import android.graphics.Color; -import android.os.Bundle; -import android.support.v7.widget.SearchView; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.widget.TextView; - -public class SearchViewPageFragment extends BaseViewPagerFragment { - - - private SearchView mSearchView; - - public static SearchViewPageFragment newInstance(){ - return new SearchViewPageFragment(); - } - - @Override - protected void onSetupTabAdapter(ViewPageFragmentAdapter adapter) { - String[] title = getResources().getStringArray(R.array.search); - adapter.addTab(title[0], "search_soft", SearchFragment.class, getBundle(SearchList.CATALOG_SOFTWARE)); - adapter.addTab(title[1], "search_quest", SearchFragment.class, getBundle(SearchList.CATALOG_POST)); - adapter.addTab(title[2], "search_blog", SearchFragment.class, getBundle(SearchList.CATALOG_BLOG)); - adapter.addTab(title[3], "search_news", SearchFragment.class, getBundle(SearchList.CATALOG_NEWS)); - } - - private Bundle getBundle(String catalog) { - Bundle bundle = new Bundle(); - bundle.putString(BaseListFragment.BUNDLE_KEY_CATALOG, catalog); - return bundle; - } - - - @Override - protected void setScreenPageLimit() { - mViewPager.setOffscreenPageLimit(3); - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - setHasOptionsMenu(true); - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - inflater.inflate(R.menu.search_menu, menu); - MenuItem search=menu.findItem(R.id.search_content); - mSearchView=(SearchView) search.getActionView(); - mSearchView.setIconifiedByDefault(false); - setSearch(); - super.onCreateOptionsMenu(menu, inflater); - } - - private void setSearch() { - mSearchView.setQueryHint("搜索"); - TextView textView = (TextView) mSearchView.findViewById(R.id.search_src_text); - textView.setTextColor(Color.WHITE); - - mSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { - - @Override - public boolean onQueryTextSubmit(String arg0) { - TDevice.hideSoftKeyboard(mSearchView); - search(arg0); - return false; - } - - @Override - public boolean onQueryTextChange(String arg0) { - return false; - } - }); - mSearchView.requestFocus(); - } - - private void search(String content) { - int index = mViewPager.getChildCount(); - for (int i = 0; i < index; i++) { - SearchFragment fragment = (SearchFragment) getChildFragmentManager().getFragments().get(i); - if (fragment != null) { - fragment.search(content); - } - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - // TODO Auto-generated method stub - return super.onOptionsItemSelected(item); - } - - @Override - public void onClick(View v) { - // TODO Auto-generated method stub - - } - - @Override - public void initView(View view) { - // TODO Auto-generated method stub - - } - - @Override - public void initData() { - // TODO Auto-generated method stub - - } - -} diff --git a/app/src/main/java/net/oschina/app/viewpagerfragment/TweetDetailViewPagerFragment.java b/app/src/main/java/net/oschina/app/viewpagerfragment/TweetDetailViewPagerFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..fb41ae1e37ebb54e4481f7b978fc14ff28400939 --- /dev/null +++ b/app/src/main/java/net/oschina/app/viewpagerfragment/TweetDetailViewPagerFragment.java @@ -0,0 +1,164 @@ +package net.oschina.app.viewpagerfragment; + +import android.app.Activity; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.design.widget.TabLayout; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentStatePagerAdapter; +import android.support.v4.view.ViewPager; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import net.oschina.app.R; +import net.oschina.app.bean.Comment; +import net.oschina.app.bean.User; +import net.oschina.app.improve.bean.simple.TweetComment; +import net.oschina.app.improve.tweet.contract.TweetDetailContract; +import net.oschina.app.improve.tweet.fragments.ListTweetCommentFragment; +import net.oschina.app.improve.tweet.fragments.ListTweetLikeUsersFragment; + +/** + * 赞 | 评论 + * Created by thanatos on 16/6/12. + * + * TweetDetailActivity TweetDetailViewPagerFragment ListTweetCommentFragment ListTweetLikeUsersFragment + * | | | | + * | on comment successful | on comment successful | | + * | ----------------------> | -------------------------->| | + * | | | | + * | on admire successful | on admire successful | + * | ----------------------> | -----------------------------------------------------> | + * | | | | + * | to reset comment count | to reset comment count | | + * | ----------------------> | <------------------------- | | + * | | | | + * | to admire comment count | to admire comment count | + * | ----------------------> | <-------------------------------------------------------| + * | | | | + * | onScroll, getTweetDetail... | | + * | <----------------------------------------------------| | + * | | | | + * | onScroll | + * |<----------------------------------------------------------------------------------| + */ +public class TweetDetailViewPagerFragment extends Fragment + implements TweetDetailContract.ICmnView, TweetDetailContract.IThumbupView, TweetDetailContract.IAgencyView { + + private ViewPager mViewPager; + private TabLayout mTabLayout; + protected FragmentStatePagerAdapter mAdapter; + private TweetDetailContract.ICmnView mCmnViewImp; + private TweetDetailContract.IThumbupView mThumbupViewImp; + private TweetDetailContract.Operator mOperator; + + public static TweetDetailViewPagerFragment instantiate(TweetDetailContract.Operator operator){ + return new TweetDetailViewPagerFragment(); + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + mOperator = (TweetDetailContract.Operator) activity; + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_tweet_view_pager, container, false); + mViewPager = (ViewPager) view.findViewById(R.id.view_pager); + mTabLayout = (TabLayout) view.findViewById(R.id.tab_nav); + return view; + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + if (mAdapter == null){ + final ListTweetLikeUsersFragment mCmnFrag; + mThumbupViewImp = mCmnFrag = ListTweetLikeUsersFragment.instantiate(mOperator, this); + + final ListTweetCommentFragment mThumbupFrag; + mCmnViewImp = mThumbupFrag = ListTweetCommentFragment.instantiate(mOperator, this); + + mViewPager.setAdapter(mAdapter = new FragmentStatePagerAdapter(getChildFragmentManager()) { + @Override + public Fragment getItem(int position) { + switch (position){ + case 0: + return mCmnFrag; + + case 1: + return mThumbupFrag; + + } + return null; + } + + @Override + public int getCount() { + return 2; + } + + @Override + public CharSequence getPageTitle(int position) { + switch (position){ + case 0: + return String.format("赞(%s)", mOperator.getTweetDetail().getLikeCount()); + case 1: + return String.format("评论(%s)", mOperator.getTweetDetail().getCommentCount()); + } + return null; + } + }); + mTabLayout.setupWithViewPager(mViewPager); + mViewPager.setCurrentItem(1); + }else{ + mViewPager.setAdapter(mAdapter); + } + } + + @Override + public void onCommentSuccess(TweetComment comment) { + mOperator.getTweetDetail().setCommentCount(mOperator.getTweetDetail().getCommentCount() + 1); // Bean的事,真不是我想这样干 + if (mCmnViewImp != null) mCmnViewImp.onCommentSuccess(comment); + TabLayout.Tab tab = mTabLayout.getTabAt(1); + if (tab != null) tab.setText(String.format("评论(%s)", mOperator.getTweetDetail().getCommentCount())); + } + + @Override + public void onLikeSuccess(boolean isUp, User user) { + mOperator.getTweetDetail().setLikeCount(mOperator.getTweetDetail().getLikeCount() + (isUp ? 1 : -1)); + if (mThumbupViewImp != null) mThumbupViewImp.onLikeSuccess(isUp, user); + TabLayout.Tab tab = mTabLayout.getTabAt(0); + if (tab != null) tab.setText(String.format("赞(%s)", mOperator.getTweetDetail().getLikeCount())); + } + + @Override + public void resetLikeCount(int count) { + mOperator.getTweetDetail().setLikeCount(count); + TabLayout.Tab tab = mTabLayout.getTabAt(0); + if (tab != null) tab.setText(String.format("赞(%s)", count)); + } + + @Override + public void resetCmnCount(int count) { + mOperator.getTweetDetail().setCommentCount(count); + TabLayout.Tab tab = mTabLayout.getTabAt(1); + if (tab != null) tab.setText(String.format("评论(%s)", count)); + } + + public TweetDetailContract.ICmnView getCommentViewHandler(){ + return this; + } + + public TweetDetailContract.IThumbupView getThumbupViewHandler(){ + return this; + } + + public TweetDetailContract.IAgencyView getAgencyViewHandler(){ + return this; + } +} diff --git a/app/src/main/java/net/oschina/app/viewpagerfragment/TweetsViewPagerFragment.java b/app/src/main/java/net/oschina/app/viewpagerfragment/TweetsViewPagerFragment.java deleted file mode 100644 index 1602951b3956ccbad45ce895e5edc4b6920624bd..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/viewpagerfragment/TweetsViewPagerFragment.java +++ /dev/null @@ -1,66 +0,0 @@ -package net.oschina.app.viewpagerfragment; - -import net.oschina.app.R; -import net.oschina.app.adapter.ViewPageFragmentAdapter; -import net.oschina.app.base.BaseListFragment; -import net.oschina.app.base.BaseViewPagerFragment; -import net.oschina.app.bean.TweetsList; -import net.oschina.app.fragment.TweetsFragment; -import net.oschina.app.interf.OnTabReselectListener; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.view.View; - -/** - * 动弹界面(包括最新动弹、热门动弹、我的动弹) - * - * @author FireAnt(http://my.oschina.net/LittleDY) - * @created 2014年9月25日 下午2:21:52 - * - */ -public class TweetsViewPagerFragment extends BaseViewPagerFragment implements - OnTabReselectListener { - - @Override - protected void onSetupTabAdapter(ViewPageFragmentAdapter adapter) { - - String[] title = getResources().getStringArray( - R.array.tweets_viewpage_arrays); - adapter.addTab(title[0], "new_tweets", TweetsFragment.class, - getBundle(TweetsList.CATALOG_LATEST)); - adapter.addTab(title[1], "hot_tweets", TweetsFragment.class, - getBundle(TweetsList.CATALOG_HOT)); - adapter.addTab(title[2], "my_tweets", TweetsFragment.class, - getBundle(TweetsList.CATALOG_ME)); - } - - private Bundle getBundle(int catalog) { - Bundle bundle = new Bundle(); - bundle.putInt(BaseListFragment.BUNDLE_KEY_CATALOG, catalog); - return bundle; - } - - @Override - public void onClick(View v) {} - - @Override - public void initView(View view) {} - - @Override - public void initData() {} - - @Override - public void onTabReselect() { - try { - int currentIndex = mViewPager.getCurrentItem(); - Fragment currentFragment = getChildFragmentManager().getFragments() - .get(currentIndex); - if (currentFragment != null - && currentFragment instanceof OnTabReselectListener) { - OnTabReselectListener listener = (OnTabReselectListener) currentFragment; - listener.onTabReselect(); - } - } catch (NullPointerException e) { - } - } -} \ No newline at end of file diff --git a/app/src/main/java/net/oschina/app/viewpagerfragment/UserFavoriteViewPagerFragment.java b/app/src/main/java/net/oschina/app/viewpagerfragment/UserFavoriteViewPagerFragment.java deleted file mode 100644 index c45621e81a12a2c18f9d3f898ec1f3d9b1468ea3..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/viewpagerfragment/UserFavoriteViewPagerFragment.java +++ /dev/null @@ -1,51 +0,0 @@ -package net.oschina.app.viewpagerfragment; - -import net.oschina.app.R; -import net.oschina.app.adapter.ViewPageFragmentAdapter; -import net.oschina.app.base.BaseListFragment; -import net.oschina.app.base.BaseViewPagerFragment; -import net.oschina.app.bean.Favorite; -import net.oschina.app.fragment.UserFavoriteFragment; -import android.os.Bundle; -import android.view.View; - -public class UserFavoriteViewPagerFragment extends BaseViewPagerFragment { - - public static UserFavoriteViewPagerFragment newInstance(){ - return new UserFavoriteViewPagerFragment(); - } - - @Override - protected void onSetupTabAdapter(ViewPageFragmentAdapter adapter) { - - String[] title = getResources().getStringArray(R.array.userfavorite); - adapter.addTab(title[0], "favorite_software", UserFavoriteFragment.class, getBundle(Favorite.CATALOG_SOFTWARE)); - adapter.addTab(title[1], "favorite_topic", UserFavoriteFragment.class, getBundle(Favorite.CATALOG_TOPIC)); - adapter.addTab(title[2], "favorite_code", UserFavoriteFragment.class, getBundle(Favorite.CATALOG_CODE)); - adapter.addTab(title[3], "favorite_blogs", UserFavoriteFragment.class, getBundle(Favorite.CATALOG_BLOGS)); - adapter.addTab(title[4], "favorite_news", UserFavoriteFragment.class, getBundle(Favorite.CATALOG_NEWS)); - - } - - private Bundle getBundle(int favoriteType) { - Bundle bundle = new Bundle(); - bundle.putInt(BaseListFragment.BUNDLE_KEY_CATALOG, favoriteType); - return bundle; - } - - @Override - public void onClick(View v) { - - } - - @Override - public void initView(View view) { - - } - - @Override - public void initData() { - - } - -} diff --git a/app/src/main/java/net/oschina/app/widget/AvatarView.java b/app/src/main/java/net/oschina/app/widget/AvatarView.java index 0ea6d39ae63cb980fc532124446d215866d172ea..bd62d0ff0f73b6bf618b98acba7f58023950522f 100644 --- a/app/src/main/java/net/oschina/app/widget/AvatarView.java +++ b/app/src/main/java/net/oschina/app/widget/AvatarView.java @@ -10,7 +10,7 @@ import net.oschina.app.R; import net.oschina.app.util.UIHelper; import org.kymjs.kjframe.Core; -import org.kymjs.kjframe.bitmap.BitmapCallBack; +import org.kymjs.kjframe.KJBitmap; import org.kymjs.kjframe.utils.StringUtils; public class AvatarView extends CircleImageView { @@ -21,6 +21,7 @@ public class AvatarView extends CircleImageView { private int id; private String name; private Activity aty; + private static KJBitmap kjb = new KJBitmap(); public AvatarView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); @@ -56,7 +57,7 @@ public class AvatarView extends CircleImageView { public void setAvatarUrl(String url) { if (StringUtils.isEmpty(url)) { - setImageResource(R.drawable.widget_dface); + setImageResource(R.mipmap.widget_dface); return; } // 由于头像地址默认加了一段参数需要去掉 @@ -68,20 +69,8 @@ public class AvatarView extends CircleImageView { headUrl = url; } - Core.getKJBitmap().display(this, headUrl, R.drawable.widget_dface, 0, 0, - new BitmapCallBack() { - @Override - public void onFailure(Exception e) { - super.onFailure(e); - aty.runOnUiThread(new Runnable() { - @Override - public void run() { - setImageResource(R.drawable.widget_dface); - } - }); - setImageResource(R.drawable.widget_dface); - } - }); + new Core.Builder().view(this).url(headUrl).errorBitmapRes(R.mipmap.widget_dface) + .loadBitmapRes(R.mipmap.widget_dface).doTask(); } public static String getSmallAvatar(String source) { diff --git a/app/src/main/java/net/oschina/app/widget/BadgeView.java b/app/src/main/java/net/oschina/app/widget/BadgeView.java deleted file mode 100644 index ea666df13ef166a11d064a694b95408ba1add96e..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/widget/BadgeView.java +++ /dev/null @@ -1,492 +0,0 @@ -package net.oschina.app.widget; - -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Color; -import android.graphics.Typeface; -import android.graphics.drawable.ShapeDrawable; -import android.graphics.drawable.shapes.RoundRectShape; -import android.util.AttributeSet; -import android.util.TypedValue; -import android.view.Gravity; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewGroup.LayoutParams; -import android.view.ViewParent; -import android.view.animation.AccelerateInterpolator; -import android.view.animation.AlphaAnimation; -import android.view.animation.Animation; -import android.view.animation.DecelerateInterpolator; -import android.widget.FrameLayout; -import android.widget.TabWidget; -import android.widget.TextView; - -/** - * A simple text label view that can be applied as a "badge" to any given - * {@link android.view.View}. This class is intended to be instantiated at - * runtime rather than included in XML layouts. - * - * @author Jeff Gilfelt - */ -public class BadgeView extends TextView { - - public static final int POSITION_TOP_LEFT = 1; - public static final int POSITION_TOP_RIGHT = 2; - public static final int POSITION_BOTTOM_LEFT = 3; - public static final int POSITION_BOTTOM_RIGHT = 4; - public static final int POSITION_CENTER = 5; - - private static final int DEFAULT_MARGIN_DIP = 5; - private static final int DEFAULT_LR_PADDING_DIP = 5; - private static final int DEFAULT_CORNER_RADIUS_DIP = 8; - private static final int DEFAULT_POSITION = POSITION_TOP_RIGHT; - private static final int DEFAULT_BADGE_COLOR = Color - .parseColor("#CCFF0000"); // Color.RED; - private static final int DEFAULT_TEXT_COLOR = Color.WHITE; - - private static Animation fadeIn; - private static Animation fadeOut; - - private Context context; - private View target; - - private int badgePosition; - private int badgeMarginH; - private int badgeMarginV; - private int badgeColor; - - private boolean isShown; - - private ShapeDrawable badgeBg; - - private int targetTabIndex; - - public BadgeView(Context context) { - this(context, (AttributeSet) null, android.R.attr.textViewStyle); - } - - public BadgeView(Context context, AttributeSet attrs) { - this(context, attrs, android.R.attr.textViewStyle); - } - - /** - * Constructor - - * - * create a new BadgeView instance attached to a target - * {@link android.view.View}. - * - * @param context - * context for this view. - * @param target - * the View to attach the badge to. - */ - public BadgeView(Context context, View target) { - this(context, null, android.R.attr.textViewStyle, target, 0); - } - - /** - * Constructor - - * - * create a new BadgeView instance attached to a target - * {@link android.widget.TabWidget} tab at a given index. - * - * @param context - * context for this view. - * @param target - * the TabWidget to attach the badge to. - * @param index - * the position of the tab within the target. - */ - public BadgeView(Context context, TabWidget target, int index) { - this(context, null, android.R.attr.textViewStyle, target, index); - } - - public BadgeView(Context context, AttributeSet attrs, int defStyle) { - this(context, attrs, defStyle, null, 0); - } - - public BadgeView(Context context, AttributeSet attrs, int defStyle, - View target, int tabIndex) { - super(context, attrs, defStyle); - init(context, target, tabIndex); - } - - private void init(Context context, View target, int tabIndex) { - - this.context = context; - this.target = target; - this.targetTabIndex = tabIndex; - - // apply defaults - badgePosition = DEFAULT_POSITION; - badgeMarginH = dipToPixels(DEFAULT_MARGIN_DIP); - badgeMarginV = badgeMarginH; - badgeColor = DEFAULT_BADGE_COLOR; - - setTypeface(Typeface.DEFAULT_BOLD); - int paddingPixels = dipToPixels(DEFAULT_LR_PADDING_DIP); - setPadding(paddingPixels, 0, paddingPixels, 0); - setTextColor(DEFAULT_TEXT_COLOR); - - fadeIn = new AlphaAnimation(0, 1); - fadeIn.setInterpolator(new DecelerateInterpolator()); - fadeIn.setDuration(200); - - fadeOut = new AlphaAnimation(1, 0); - fadeOut.setInterpolator(new AccelerateInterpolator()); - fadeOut.setDuration(200); - - isShown = false; - - if (this.target != null) { - applyTo(this.target); - } else { - show(); - } - } - - private void applyTo(View target) { - - LayoutParams lp = target.getLayoutParams(); - ViewParent parent = target.getParent(); - FrameLayout container = new FrameLayout(context); - - if (target instanceof TabWidget) { - // set target to the relevant tab child container - target = ((TabWidget) target).getChildTabViewAt(targetTabIndex); - this.target = target; - - ((ViewGroup) target).addView(container, new LayoutParams( - LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); - - this.setVisibility(View.GONE); - container.addView(this); - - } else { - // TODO verify that parent is indeed a ViewGroup - ViewGroup group = (ViewGroup) parent; - int index = group.indexOfChild(target); - - group.removeView(target); - group.addView(container, index, lp); - - container.addView(target); - - this.setVisibility(View.GONE); - container.addView(this); - group.invalidate(); - - } - } - - /** - * Make the badge visible in the UI. - * - */ - public void show() { - show(false, null); - } - - /** - * Make the badge visible in the UI. - * - * @param animate - * flag to apply the default fade-in animation. - */ - public void show(boolean animate) { - show(animate, fadeIn); - } - - /** - * Make the badge visible in the UI. - * - * @param anim - * Animation to apply to the view when made visible. - */ - public void show(Animation anim) { - show(true, anim); - } - - /** - * Make the badge non-visible in the UI. - * - */ - public void hide() { - hide(false, null); - } - - /** - * Make the badge non-visible in the UI. - * - * @param animate - * flag to apply the default fade-out animation. - */ - public void hide(boolean animate) { - hide(animate, fadeOut); - } - - /** - * Make the badge non-visible in the UI. - * - * @param anim - * Animation to apply to the view when made non-visible. - */ - public void hide(Animation anim) { - hide(true, anim); - } - - /** - * Toggle the badge visibility in the UI. - * - */ - public void toggle() { - toggle(false, null, null); - } - - /** - * Toggle the badge visibility in the UI. - * - * @param animate - * flag to apply the default fade-in/out animation. - */ - public void toggle(boolean animate) { - toggle(animate, fadeIn, fadeOut); - } - - /** - * Toggle the badge visibility in the UI. - * - * @param animIn - * Animation to apply to the view when made visible. - * @param animOut - * Animation to apply to the view when made non-visible. - */ - public void toggle(Animation animIn, Animation animOut) { - toggle(true, animIn, animOut); - } - - private void show(boolean animate, Animation anim) { - if (getBackground() == null) { - if (badgeBg == null) { - badgeBg = getDefaultBackground(); - } - setBackgroundDrawable(badgeBg); - } - applyLayoutParams(); - - if (animate) { - this.startAnimation(anim); - } - this.setVisibility(View.VISIBLE); - isShown = true; - } - - private void hide(boolean animate, Animation anim) { - this.setVisibility(View.GONE); - if (animate) { - this.startAnimation(anim); - } - isShown = false; - } - - private void toggle(boolean animate, Animation animIn, Animation animOut) { - if (isShown) { - hide(animate && (animOut != null), animOut); - } else { - show(animate && (animIn != null), animIn); - } - } - - /** - * Increment the numeric badge label. If the current badge label cannot be - * converted to an integer value, its label will be set to "0". - * - * @param offset - * the increment offset. - */ - public int increment(int offset) { - CharSequence txt = getText(); - int i; - if (txt != null) { - try { - i = Integer.parseInt(txt.toString()); - } catch (NumberFormatException e) { - i = 0; - } - } else { - i = 0; - } - i = i + offset; - setText(String.valueOf(i)); - return i; - } - - /** - * Decrement the numeric badge label. If the current badge label cannot be - * converted to an integer value, its label will be set to "0". - * - * @param offset - * the decrement offset. - */ - public int decrement(int offset) { - return increment(-offset); - } - - private ShapeDrawable getDefaultBackground() { - - int r = dipToPixels(DEFAULT_CORNER_RADIUS_DIP); - float[] outerR = new float[] { r, r, r, r, r, r, r, r }; - - RoundRectShape rr = new RoundRectShape(outerR, null, null); - ShapeDrawable drawable = new ShapeDrawable(rr); - drawable.getPaint().setColor(badgeColor); - - return drawable; - - } - - private void applyLayoutParams() { - - FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( - LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); - - switch (badgePosition) { - case POSITION_TOP_LEFT: - lp.gravity = Gravity.LEFT | Gravity.TOP; - lp.setMargins(badgeMarginH, badgeMarginV, 0, 0); - break; - case POSITION_TOP_RIGHT: - lp.gravity = Gravity.RIGHT | Gravity.TOP; - lp.setMargins(0, badgeMarginV, badgeMarginH, 0); - break; - case POSITION_BOTTOM_LEFT: - lp.gravity = Gravity.LEFT | Gravity.BOTTOM; - lp.setMargins(badgeMarginH, 0, 0, badgeMarginV); - break; - case POSITION_BOTTOM_RIGHT: - lp.gravity = Gravity.RIGHT | Gravity.BOTTOM; - lp.setMargins(0, 0, badgeMarginH, badgeMarginV); - break; - case POSITION_CENTER: - lp.gravity = Gravity.CENTER; - lp.setMargins(0, 0, 0, 0); - break; - default: - break; - } - - setLayoutParams(lp); - - } - - /** - * Returns the target View this badge has been attached to. - * - */ - public View getTarget() { - return target; - } - - /** - * Is this badge currently visible in the UI? - * - */ - @Override - public boolean isShown() { - return isShown; - } - - /** - * Returns the positioning of this badge. - * - * one of POSITION_TOP_LEFT, POSITION_TOP_RIGHT, POSITION_BOTTOM_LEFT, - * POSITION_BOTTOM_RIGHT, POSTION_CENTER. - * - */ - public int getBadgePosition() { - return badgePosition; - } - - /** - * Set the positioning of this badge. - * - * @param layoutPosition - * one of POSITION_TOP_LEFT, POSITION_TOP_RIGHT, - * POSITION_BOTTOM_LEFT, POSITION_BOTTOM_RIGHT, POSTION_CENTER. - * - */ - public void setBadgePosition(int layoutPosition) { - this.badgePosition = layoutPosition; - } - - /** - * Returns the horizontal margin from the target View that is applied to - * this badge. - * - */ - public int getHorizontalBadgeMargin() { - return badgeMarginH; - } - - /** - * Returns the vertical margin from the target View that is applied to this - * badge. - * - */ - public int getVerticalBadgeMargin() { - return badgeMarginV; - } - - /** - * Set the horizontal/vertical margin from the target View that is applied - * to this badge. - * - * @param badgeMargin - * the margin in pixels. - */ - public void setBadgeMargin(int badgeMargin) { - this.badgeMarginH = badgeMargin; - this.badgeMarginV = badgeMargin; - } - - /** - * Set the horizontal/vertical margin from the target View that is applied - * to this badge. - * - * @param horizontal - * margin in pixels. - * @param vertical - * margin in pixels. - */ - public void setBadgeMargin(int horizontal, int vertical) { - this.badgeMarginH = horizontal; - this.badgeMarginV = vertical; - } - - /** - * Returns the color value of the badge background. - * - */ - public int getBadgeBackgroundColor() { - return badgeColor; - } - - /** - * Set the color value of the badge background. - * - * @param badgeColor - * the badge background color. - */ - public void setBadgeBackgroundColor(int badgeColor) { - this.badgeColor = badgeColor; - badgeBg = getDefaultBackground(); - } - - private int dipToPixels(int dip) { - Resources r = getResources(); - float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, - r.getDisplayMetrics()); - return (int) px; - } - -} diff --git a/app/src/main/java/net/oschina/app/widget/HackyViewPager.java b/app/src/main/java/net/oschina/app/widget/HackyViewPager.java deleted file mode 100644 index 3b53ce3af107efb9c179f390fd231654fa687fb4..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/widget/HackyViewPager.java +++ /dev/null @@ -1,72 +0,0 @@ -package net.oschina.app.widget; - -import android.content.Context; -import android.support.v4.view.ViewPager; -import android.util.AttributeSet; -import android.view.MotionEvent; - -/** - * Found at http://stackoverflow.com/questions/7814017/is-it-possible-to-disable-scrolling-on-a-viewpager. - * Convenient way to temporarily disable ViewPager navigation while interacting with ImageView. - * - * Julia Zudikova - */ - -/** - * Hacky fix for Issue #4 and - * http://code.google.com/p/android/issues/detail?id=18990 - *

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

    - * There's not much I can do in my code for now, but we can mask the result by - * just catching the problem and ignoring it. - * - * @author Chris Banes - */ -public class HackyViewPager extends ViewPager { - - private boolean isLocked; - - public HackyViewPager(Context context) { - super(context); - isLocked = false; - } - - public HackyViewPager(Context context, AttributeSet attrs) { - super(context, attrs); - isLocked = false; - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - if (!isLocked) { - try { - return super.onInterceptTouchEvent(ev); - } catch (IllegalArgumentException e) { - e.printStackTrace(); - return false; - } - } - return false; - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - return !isLocked && super.onTouchEvent(event); - } - - public void toggleLock() { - isLocked = !isLocked; - } - - public void setLocked(boolean isLocked) { - this.isLocked = isLocked; - } - - public boolean isLocked() { - return isLocked; - } - -} diff --git a/app/src/main/java/net/oschina/app/widget/HolderTextView.java b/app/src/main/java/net/oschina/app/widget/HolderTextView.java deleted file mode 100644 index aaff85b335ca2eaec051f21b26bc97c8f32ecf27..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/widget/HolderTextView.java +++ /dev/null @@ -1,17 +0,0 @@ -package net.oschina.app.widget; - -import net.oschina.app.R; -import android.content.Context; -import android.view.Gravity; -import android.widget.TextView; - -public class HolderTextView extends TextView { - - public HolderTextView(Context context) { - super(context); - setTextSize(getResources().getDimension(R.dimen.text_size_10)); - setGravity(Gravity.CENTER_VERTICAL); - setPadding((int) getResources().getDimension(R.dimen.text_size_30), 10, - 0, 10); - } -} diff --git a/app/src/main/java/net/oschina/app/widget/IndexView.java b/app/src/main/java/net/oschina/app/widget/IndexView.java index 36a8c9bc04250f4df5a753896e8094be50bac828..b2025774843259ff757ab413ed9b6e2839ca0156 100644 --- a/app/src/main/java/net/oschina/app/widget/IndexView.java +++ b/app/src/main/java/net/oschina/app/widget/IndexView.java @@ -15,14 +15,14 @@ import android.view.View; *

    LeonLee Blog

    * * @author 李文龙(LeonLee) - * - * 索引界面 + *

    + * 索引界面 */ public class IndexView extends View { private static final String DEFAULT_INDEX = "☆ABCDEFGHIJKLMNOPQRSTUVWXYZ#"; - private static final int[] ATTRS = new int[] { + private static final int[] ATTRS = new int[]{ android.R.attr.textSize, android.R.attr.textColor, }; @@ -47,6 +47,7 @@ public class IndexView extends View { this(context, attrs, 0); } + @SuppressWarnings("ResourceType") public IndexView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); @@ -71,12 +72,12 @@ public class IndexView extends View { @Override public void draw(Canvas canvas) { super.draw(canvas); - if(indexLetters == null || indexLetters.length == 0) { + if (indexLetters == null || indexLetters.length == 0) { return; } final int width = getWidth(); - if(!isInitItemHeight) { + if (!isInitItemHeight) { final int height = getHeight() - getPaddingTop() - getPaddingBottom(); itemHeight = height / indexLetters.length; final Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt(); @@ -86,7 +87,7 @@ public class IndexView extends View { } int x; - for(int i = 0; i < indexLetters.length; i ++) { + for (int i = 0; i < indexLetters.length; i++) { String indexStr = String.valueOf(indexLetters[i]); x = (int) ((width - paint.measureText(indexStr)) * 0.5); canvas.drawText(indexStr, x, offsetY + itemHeight * i, paint); @@ -95,7 +96,7 @@ public class IndexView extends View { @Override public boolean onTouchEvent(MotionEvent event) { - if(itemHeight == 0) { + if (itemHeight == 0) { return false; } int action = MotionEventCompat.getActionMasked(event); @@ -129,6 +130,7 @@ public class IndexView extends View { public interface OnIndexTouchListener { public void onIndexTouchMove(char indexLeter); + public void onIndexTouchUp(); } } diff --git a/app/src/main/java/net/oschina/app/widget/KJScrollView.java b/app/src/main/java/net/oschina/app/widget/KJScrollView.java deleted file mode 100644 index 12e582a7489b4a7199d4016090d82b54706decf5..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/widget/KJScrollView.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (c) 2014, KJFrameForAndroid 张涛 (kymjs123@gmail.com). - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package net.oschina.app.widget; - -import android.content.Context; -import android.graphics.Rect; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; -import android.view.animation.TranslateAnimation; -import android.widget.ScrollView; - -/** - * 有弹性的ScrollView 实现下拉弹回和上拉弹回
    - * - * 创建时间 2014-7-5 - * - * @author kymjs(kymjs123@gmail.com) - * @version 1.0 - */ -public class KJScrollView extends ScrollView { - - // data - private static final float MOVE_FACTOR = 0.5f; // 移动因子,手指移动100px,那么View就只移动50px - - private static final int ANIM_TIME = 300; // 松开手指后, 界面回到正常位置需要的动画时间 - - private float startY;// 手指按下时的Y值, 用于在移动时计算移动距离,如果按下时不能上拉和下拉, - // 会在手指移动时更新为当前手指的Y值 - - // ui - private View contentView; // ScrollView的唯一内容控件 - private final Rect originalRect = new Rect();// 用于记录正常的布局位置 - - // flag - private boolean canPullDown = false; // 是否可以继续下拉 - private boolean canPullUp = false; // 是否可以继续上拉 - private boolean isMoved = false; // 记录是否移动了布局 - - public KJScrollView(Context context) { - super(context); - } - - public KJScrollView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected void onFinishInflate() { - if (getChildCount() > 0) { - contentView = getChildAt(0); - } - } - - @Override - public void addView(View child) { - super.addView(child); - onFinishInflate(); - } - - @Override - public void addView(View child, int index) { - super.addView(child, index); - onFinishInflate(); - } - - @Override - public void addView(View child, int width, int height) { - super.addView(child, width, height); - onFinishInflate(); - } - - @Override - public void addView(View child, int index, - android.view.ViewGroup.LayoutParams params) { - super.addView(child, index, params); - onFinishInflate(); - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - super.onLayout(changed, l, t, r, b); - if (contentView == null) - return; - // ScrollView中的唯一子控件的位置信息, 这个位置信息在整个控件的生命周期中保持不变 - originalRect.set(contentView.getLeft(), contentView.getTop(), - contentView.getRight(), contentView.getBottom()); - } - - /** - * 在触摸事件中, 处理上拉和下拉的逻辑 - */ - @Override - public boolean dispatchTouchEvent(MotionEvent ev) { - if (contentView == null) { - return super.dispatchTouchEvent(ev); - } - // 手指是否移动到了当前ScrollView控件之外 - boolean isTouchOutOfScrollView = ev.getY() >= this.getHeight() - || ev.getY() <= 0; - if (isTouchOutOfScrollView) { // 如果移动到了当前ScrollView控件之外 - if (isMoved) {// 如果当前contentView已经被移动, 首先把布局移到原位置 - boundBack(); - } - return true; - } - int action = ev.getAction(); - switch (action) { - case MotionEvent.ACTION_DOWN: - // 判断是否可以上拉和下拉 - canPullDown = isCanPullDown(); - canPullUp = isCanPullUp(); - // 记录按下时的Y值 - startY = ev.getY(); - break; - case MotionEvent.ACTION_UP: - boundBack(); - break; - case MotionEvent.ACTION_MOVE: - // 在移动的过程中, 既没有滚动到可以上拉的程度, 也没有滚动到可以下拉的程度 - if (!canPullDown && !canPullUp) { - startY = ev.getY(); - canPullDown = isCanPullDown(); - canPullUp = isCanPullUp(); - break; - } - // 计算手指移动的距离 - float nowY = ev.getY(); - int deltaY = (int) (nowY - startY); - - // 是否应该移动布局 - boolean shouldMove = (canPullDown && deltaY > 0) // 可以下拉, 并且手指向下移动 - || (canPullUp && deltaY < 0) // 可以上拉, 并且手指向上移动 - || (canPullUp && canPullDown); // 既可以上拉也可以下拉(这种情况出现在ScrollView包裹的控件比ScrollView还小) - if (shouldMove) { - // 计算偏移量 - int offset = (int) (deltaY * MOVE_FACTOR); - // 随着手指的移动而移动布局 - contentView.layout(originalRect.left, - originalRect.top + offset, originalRect.right, - originalRect.bottom + offset); - isMoved = true; // 记录移动了布局 - } - break; - } - return super.dispatchTouchEvent(ev); - } - - /** - * 将内容布局移动到原位置 可以在UP事件中调用, 也可以在其他需要的地方调用, 如手指移动到当前ScrollView外时 - */ - private void boundBack() { - if (!isMoved) { - return; // 如果没有移动布局, 则跳过执行 - } - // 开启动画 - TranslateAnimation anim = new TranslateAnimation(0, 0, - contentView.getTop(), originalRect.top); - anim.setDuration(ANIM_TIME); - contentView.startAnimation(anim); - // 设置回到正常的布局位置 - contentView.layout(originalRect.left, originalRect.top, - originalRect.right, originalRect.bottom); - // 将标志位设回false - canPullDown = false; - canPullUp = false; - isMoved = false; - } - - /** - * 判断是否滚动到顶部 - */ - private boolean isCanPullDown() { - return getScrollY() == 0 - || contentView.getHeight() < getHeight() + getScrollY(); - } - - /** - * 判断是否滚动到底部 - */ - private boolean isCanPullUp() { - return contentView.getHeight() <= getHeight() + getScrollY(); - } -} \ No newline at end of file diff --git a/app/src/main/java/net/oschina/app/widget/LinkView.java b/app/src/main/java/net/oschina/app/widget/LinkView.java deleted file mode 100644 index e963dc99846e70b36f5c0fabbf39138f53ba3c25..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/widget/LinkView.java +++ /dev/null @@ -1,183 +0,0 @@ -package net.oschina.app.widget; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import net.oschina.app.util.URLsUtils; -import android.content.Context; -import android.graphics.Color; -import android.text.Html; -import android.text.Spannable; -import android.text.SpannableStringBuilder; -import android.text.Spanned; -import android.text.TextPaint; -import android.text.method.LinkMovementMethod; -import android.text.style.ClickableSpan; -import android.text.style.URLSpan; -import android.util.AttributeSet; -import android.view.View; -import android.widget.TextView; - -/** - * @author HuangWenwei - * - * @date 2014年10月10日 - */ -public class LinkView extends TextView { - private OnLinkClickListener mLinkClickListener = new LinkView.OnLinkClickListener() { - @Override - public void onLinkClick() { - - } - }; - - public LinkView(Context context) { - super(context); - } - - public LinkView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public LinkView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - public OnLinkClickListener getLinkClickListener() { - return mLinkClickListener; - } - - public void setLinkClickListener(OnLinkClickListener linkClickListener) { - this.mLinkClickListener = linkClickListener; - } - - public final static Pattern WECHAT_REG = Pattern - .compile("(<{1}img[\\s]+class=\"wechat-emoji\"[\\s]+src=\"[^<]+\"[\\s]+alt=\"([^<\\s\"]+)\"[\\s]+[^<]*[>]{1})"); - - private static String filterWechat(String linktxt) { - System.out.println(linktxt); - if (null == linktxt) - return ""; - try { - Matcher match = WECHAT_REG.matcher(linktxt); - if (null == match) - return linktxt; - while (match.find()) { - String target = match.group(1); - String rp = match.group(2); - linktxt = linktxt.replace(target, "[" + rp + "]"); - } - } catch (Exception e) { - return linktxt; - } - return linktxt; - } - - public void setLinkText(String linktxt) { - linktxt = filterWechat(linktxt); - Spanned span = Html.fromHtml(linktxt); - setText(span); - setMovementMethod(LinkMovementMethod.getInstance()); - parseLinkText(span); - } - - public void parseLinkText(Spanned spanhtml) { - CharSequence text = getText(); - if (text instanceof Spannable) { - int end = text.length(); - Spannable sp = (Spannable) getText(); - URLSpan[] urls = sp.getSpans(0, end, URLSpan.class); - - URLSpan[] htmlurls = spanhtml != null ? spanhtml.getSpans(0, end, - URLSpan.class) : new URLSpan[] {}; - - if (urls.length == 0 && htmlurls.length == 0) - return; - - SpannableStringBuilder style = new SpannableStringBuilder(text); - // style.clearSpans();// 这里会清除之前所有的样式 - for (URLSpan url : urls) { - if (!isNormalUrl(url)) { - style.removeSpan(url);// 只需要移除之前的URL样式,再重新设置 - NoLinkSpan span = new NoLinkSpan(url.getURL()); - style.setSpan(span, sp.getSpanStart(url), - sp.getSpanEnd(url), - Spannable.SPAN_INCLUSIVE_EXCLUSIVE); - continue; - } - style.removeSpan(url);// 只需要移除之前的URL样式,再重新设置 - MyURLSpan myURLSpan = new MyURLSpan(url.getURL()); - style.setSpan(myURLSpan, sp.getSpanStart(url), - sp.getSpanEnd(url), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - } - for (URLSpan url : htmlurls) { - style.removeSpan(url);// 只需要移除之前的URL样式,再重新设置 - MyURLSpan myURLSpan = new MyURLSpan(url.getURL()); - style.setSpan(myURLSpan, spanhtml.getSpanStart(url), - spanhtml.getSpanEnd(url), - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - } - setText(style); - } - } - - public void parseLinkText() { - parseLinkText(null); - } - - public class MyURLSpan extends ClickableSpan { - private String mUrl; - - public MyURLSpan(String url) { - mUrl = url; - } - - @Override - public void onClick(View widget) { - mLinkClickListener.onLinkClick(); - URLsUtils urls = URLsUtils.parseURL(mUrl); - if (urls != null) { - //UIHelper.showLinkRedirect(widget.getContext(), - // urls.getObjType(), urls.getObjId(), urls.getObjKey()); - } else { - // UIHelper.openBrowser(widget.getContext(), mUrl); - } - } - } - - public class NoLinkSpan extends ClickableSpan { - private String text; - public NoLinkSpan(String text) { - super(); - this.text = text; - } - - @Override - public void updateDrawState(TextPaint ds) { - ds.setColor(Color.BLACK); - ds.setUnderlineText(false); // 去掉下划线 - } - - @Override - public void onClick(View widget) { - } - - } - - public interface OnLinkClickListener { - void onLinkClick(); - } - - /** - * 过滤掉一些不正常的链接 - * @param url - * @return - */ - public boolean isNormalUrl(URLSpan url) { - String urlStr = url.getURL(); - if (urlStr.endsWith(".sh")) { - return false; - } - return true; - } -} diff --git a/app/src/main/java/net/oschina/app/widget/MyURLSpan.java b/app/src/main/java/net/oschina/app/widget/MyURLSpan.java index 81d7ed9920fc59fe9a157b64fae9722979a601e0..44d65c570a4ed6d6c0ee89cc611bd39773ab8e09 100644 --- a/app/src/main/java/net/oschina/app/widget/MyURLSpan.java +++ b/app/src/main/java/net/oschina/app/widget/MyURLSpan.java @@ -8,8 +8,7 @@ import android.text.style.URLSpan; import android.view.View; import android.widget.TextView; -import net.oschina.app.util.UIHelper; -import net.oschina.app.util.URLsUtils; +import net.oschina.app.improve.utils.URLUtils; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -135,13 +134,7 @@ public class MyURLSpan extends URLSpan { @Override public void onClick(View widget) { - URLsUtils urls = URLsUtils.parseURL(getURL()); - if (urls != null) { - UIHelper.showLinkRedirect(widget.getContext(), urls.getObjType(), - urls.getObjId(), urls.getObjKey()); - } else { - UIHelper.openBrowser(widget.getContext(), getURL()); - } + URLUtils.parseUrl(widget.getContext(), getURL()); } public static void parseLinkText(TextView widget, Spanned spanhtml) { diff --git a/app/src/main/java/net/oschina/app/widget/RecordButton.java b/app/src/main/java/net/oschina/app/widget/RecordButton.java index ccb4cfdfffe77286a488351fc9d09fb110398c92..32ce9906edaae984b261d40d3f5b235db40d2dc7 100644 --- a/app/src/main/java/net/oschina/app/widget/RecordButton.java +++ b/app/src/main/java/net/oschina/app/widget/RecordButton.java @@ -192,16 +192,16 @@ public class RecordButton extends RelativeLayout { case 0: case 1: case 2: - mImgVolume.setImageResource(R.drawable.audio0); + mImgVolume.setImageResource(R.mipmap.audio0); break; case 3: - mImgVolume.setImageResource(R.drawable.audio1); + mImgVolume.setImageResource(R.mipmap.audio1); break; case 4: - mImgVolume.setImageResource(R.drawable.audio2); + mImgVolume.setImageResource(R.mipmap.audio2); break; case 5: - mImgVolume.setImageResource(R.drawable.audio3); + mImgVolume.setImageResource(R.mipmap.audio3); break; } } diff --git a/app/src/main/java/net/oschina/app/widget/RecordDialog.java b/app/src/main/java/net/oschina/app/widget/RecordDialog.java deleted file mode 100644 index 0ecb691a6759de019cf529933d031926e6d82465..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/widget/RecordDialog.java +++ /dev/null @@ -1,59 +0,0 @@ -package net.oschina.app.widget; - -import net.oschina.app.R; -import android.app.Dialog; -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.drawable.Drawable; -import android.view.View; -import android.view.Window; -import android.widget.ImageView; - -/** - * 弹出的指示音量大小的dialog - * - * @author kymjs(kymjs123@gmail.com) - * - */ -public class RecordDialog extends Dialog { - - private ImageView mImgVolume; - - public RecordDialog(Context context) { - super(context); - init(); - } - - public RecordDialog(Context context, int theme) { - super(context, theme); - init(); - } - - protected RecordDialog(Context context, boolean cancelable, - OnCancelListener cancelListener) { - super(context, cancelable, cancelListener); - init(); - } - - private void init() { - requestWindowFeature(Window.FEATURE_NO_TITLE); - View rootView = View - .inflate(getContext(), R.layout.dialog_record, null); - mImgVolume = (ImageView) rootView - .findViewById(R.id.dialog_img_record_volume); - setContentView(rootView); - } - - public void setImageResource(int resId) { - mImgVolume.setImageResource(resId); - } - - public void setImageBitmap(Bitmap bitmap) { - mImgVolume.setImageBitmap(bitmap); - } - - public void setImageDrawable(Drawable drawable) { - mImgVolume.setImageDrawable(drawable); - } - -} diff --git a/app/src/main/java/net/oschina/app/widget/SuperRefreshLayout.java b/app/src/main/java/net/oschina/app/widget/SuperRefreshLayout.java new file mode 100644 index 0000000000000000000000000000000000000000..15db6d1fffa4e994ddf3658f75b263269ab0bd17 --- /dev/null +++ b/app/src/main/java/net/oschina/app/widget/SuperRefreshLayout.java @@ -0,0 +1,200 @@ +package net.oschina.app.widget; + +import android.content.Context; +import android.support.v4.widget.SwipeRefreshLayout; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; +import android.widget.AbsListView; +import android.widget.ListView; + +/** + * Created by huanghaibin + * on 2016/5/23. + */ +@SuppressWarnings("unused") +public class SuperRefreshLayout extends SwipeRefreshLayout implements AbsListView.OnScrollListener, SwipeRefreshLayout.OnRefreshListener { + private ListView mListView; + + private int mTouchSlop; + + private SuperRefreshLayoutListener mListener; + + private boolean mIsOnLoading = false; + + private boolean mCanLoadMore = false; + + private int mYDown; + + private int mLastY; + + private int mTextColor; + private int mFooterBackground; + private boolean mIsMoving = false; + + public SuperRefreshLayout(Context context) { + this(context, null); + } + + public SuperRefreshLayout(Context context, AttributeSet attrs) { + super(context, attrs); + mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); + setOnRefreshListener(this); + } + + @Override + public void onScrollStateChanged(AbsListView view, int scrollState) { + + } + + @Override + public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { + // 滚动时到了最底部也可以加载更多 + if (canLoad()) { + loadData(); + } + } + + @Override + public void onRefresh() { + if (mListener != null && !mIsOnLoading) { + mListener.onRefreshing(); + } + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + // 初始化ListView对象 + if (mListView == null) { + getListView(); + } + } + + /** + * 获取ListView并添加Footer + */ + private void getListView() { + int child = getChildCount(); + if (child > 0) { + View childView = getChildAt(0); + if (childView instanceof ListView) { + mListView = (ListView) childView; + // 设置滚动监听器给ListView, 使得滚动的情况下也可以自动加载 + mListView.setOnScrollListener(this); + } + } + } + + + public void setCanLoadMore() { + this.mCanLoadMore = true; + } + + public void setNoMoreData() { + this.mCanLoadMore = false; + } + + @Override + public boolean dispatchTouchEvent(MotionEvent event) { + final int action = event.getAction(); + switch (action) { + case MotionEvent.ACTION_DOWN: + // 按下 + mYDown = (int) event.getRawY(); + break; + + case MotionEvent.ACTION_MOVE: + // 移动 + mIsMoving = true; + mLastY = (int) event.getRawY(); + break; + case MotionEvent.ACTION_UP: + mIsMoving = false; + break; + default: + break; + } + return super.dispatchTouchEvent(event); + } + + /** + * 是否可以加载更多, 条件是到了最底部, listview不在加载中, 且为上拉操作. + * + * @return 是否可以加载更多 + */ + private boolean canLoad() { + return isInBottom() && !mIsOnLoading && isPullUp() && mCanLoadMore; + } + + /** + * 如果到了最底部,而且是上拉操作.那么执行onLoad方法 + */ + private void loadData() { + if (mListener != null) { + setIsOnLoading(true); + mListener.onLoadMore(); + } + } + + /** + * 是否是上拉操作 + * + * @return 是否是上拉操作 + */ + private boolean isPullUp() { + return (mYDown - mLastY) >= mTouchSlop; + } + + /** + * 设置正在加载 + * + * @param loading loading + */ + public void setIsOnLoading(boolean loading) { + mIsOnLoading = loading; + if (!mIsOnLoading) { + mYDown = 0; + mLastY = 0; + } + } + + + /** + * 判断是否到了最底部 + */ + private boolean isInBottom() { + return (mListView != null && mListView.getAdapter() != null) + && mListView.getLastVisiblePosition() == (mListView.getAdapter().getCount() - 1); + } + + + public interface SuperRefreshLayoutListener { + void onRefreshing(); + + void onLoadMore(); + } + + + /** + * 加载结束记得调用 + */ + public void onLoadComplete() { + setIsOnLoading(false); + setRefreshing(false); + } + + /** + * set + * + * @param loadListener loadListener + */ + public void setSuperRefreshLayoutListener(SuperRefreshLayoutListener loadListener) { + mListener = loadListener; + } + + public boolean isMoving() { + return mIsMoving; + } +} diff --git a/app/src/main/java/net/oschina/app/widget/TouchImageView.java b/app/src/main/java/net/oschina/app/widget/TouchImageView.java new file mode 100644 index 0000000000000000000000000000000000000000..82575a9ac8aa0b3f25dc5b70b66520833dadeac6 --- /dev/null +++ b/app/src/main/java/net/oschina/app/widget/TouchImageView.java @@ -0,0 +1,1279 @@ +package net.oschina.app.widget; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.res.Configuration; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.PointF; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.Build.VERSION; +import android.os.Build.VERSION_CODES; +import android.os.Bundle; +import android.os.Parcelable; +import android.util.AttributeSet; +import android.util.Log; +import android.view.GestureDetector; +import android.view.MotionEvent; +import android.view.ScaleGestureDetector; +import android.view.View; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.widget.ImageView; +import android.widget.OverScroller; +import android.widget.Scroller; + +/** + * Created by serhatsurguvec on 10/14/15. + */ +/* + * TouchImageView.java + * By: Michael Ortiz + * Updated By: Patrick Lackemacher + * Updated By: Babay88 + * Updated By: @ipsilondev + * Updated By: hank-cp + * Updated By: singpolyma + * ------------------- + * Extends Android ImageView to include pinch zooming, panning, fling and double tap zoom. + */ +public class TouchImageView extends ImageView { + + private final String TAG = getClass().getName(); + + private static final String DEBUG = "DEBUG"; + + // + // SuperMin and SuperMax multipliers. Determine how much the image can be + // zoomed below or above the zoom boundaries, before animating back to the + // min/max zoom boundary. + // + private static final float SUPER_MIN_MULTIPLIER = .75f; + private static final float SUPER_MAX_MULTIPLIER = 1.25f; + + // + // Scale of image ranges from minScale to maxScale, where minScale == 1 + // when the image is stretched to fit view. + // + private float normalizedScale; + + // + // Matrix applied to image. MSCALE_X and MSCALE_Y should always be equal. + // MTRANS_X and MTRANS_Y are the other values used. prevMatrix is the matrix + // saved prior to the screen rotating. + // + private Matrix matrix, prevMatrix; + + private static enum State {NONE, DRAG, ZOOM, FLING, ANIMATE_ZOOM} + private State state; + + private float minScale; + private float maxScale; + private float superMinScale; + private float superMaxScale; + private float[] m; + + private Context context; + private Fling fling; + + private ScaleType mScaleType; + + private boolean imageRenderedAtLeastOnce; + private boolean onDrawReady; + + private ZoomVariables delayedZoomVariables; + + // + // Size of view and previous view size (ie before rotation) + // + private int viewWidth, viewHeight, prevViewWidth, prevViewHeight; + + // + // Size of image when it is stretched to fit view. Before and After rotation. + // + private float matchViewWidth, matchViewHeight, prevMatchViewWidth, prevMatchViewHeight; + + private ScaleGestureDetector mScaleDetector; + private GestureDetector mGestureDetector; + private GestureDetector.OnDoubleTapListener doubleTapListener = null; + private OnTouchListener userTouchListener = null; + private OnTouchImageViewListener touchImageViewListener = null; + + public TouchImageView(Context context) { + super(context); + sharedConstructing(context); + } + + public TouchImageView(Context context, AttributeSet attrs) { + super(context, attrs); + sharedConstructing(context); + } + + public TouchImageView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + sharedConstructing(context); + } + + private void sharedConstructing(Context context) { + super.setClickable(true); + this.context = context; + mScaleDetector = new ScaleGestureDetector(context, new ScaleListener()); + mGestureDetector = new GestureDetector(context, new GestureListener()); + matrix = new Matrix(); + prevMatrix = new Matrix(); + m = new float[9]; + normalizedScale = 1; + if (mScaleType == null) { + mScaleType = ScaleType.MATRIX; + } + minScale = 1; + maxScale = 4; + superMinScale = SUPER_MIN_MULTIPLIER * minScale; + superMaxScale = SUPER_MAX_MULTIPLIER * maxScale; + setImageMatrix(matrix); + setScaleType(ScaleType.MATRIX); + setState(State.NONE); + onDrawReady = false; + super.setOnTouchListener(new PrivateOnTouchListener()); + } + + @Override + public void setOnTouchListener(OnTouchListener l) { + userTouchListener = l; + } + + public void setOnTouchImageViewListener(OnTouchImageViewListener l) { + touchImageViewListener = l; + } + + public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener l) { + doubleTapListener = l; + } + + @Override + public void setImageResource(int resId) { + super.setImageResource(resId); + savePreviousImageValues(); + fitImageToView(); + } + + @Override + public void setImageBitmap(Bitmap bm) { + super.setImageBitmap(bm); + savePreviousImageValues(); + fitImageToView(); + } + + @Override + public void setImageDrawable(Drawable drawable) { + super.setImageDrawable(drawable); + savePreviousImageValues(); + fitImageToView(); + } + + @Override + public void setImageURI(Uri uri) { + super.setImageURI(uri); + savePreviousImageValues(); + fitImageToView(); + } + + @Override + public void setScaleType(ScaleType type) { + if (type == ScaleType.FIT_START || type == ScaleType.FIT_END) { + throw new UnsupportedOperationException("TouchImageView does not support FIT_START or FIT_END"); + } + if (type == ScaleType.MATRIX) { + super.setScaleType(ScaleType.MATRIX); + + } else { + mScaleType = type; + if (onDrawReady) { + // + // If the image is already rendered, scaleType has been called programmatically + // and the TouchImageView should be updated with the new scaleType. + // + setZoom(this); + } + } + } + + @Override + public ScaleType getScaleType() { + return mScaleType; + } + + /** + * Returns false if image is in initial, unzoomed state. False, otherwise. + * + * @return true if image is zoomed + */ + public boolean isZoomed() { + return normalizedScale != 1; + } + + /** + * Return a Rect representing the zoomed image. + * + * @return rect representing zoomed image + */ + public RectF getZoomedRect() { + if (mScaleType == ScaleType.FIT_XY) { + throw new UnsupportedOperationException("getZoomedRect() not supported with FIT_XY"); + } + PointF topLeft = transformCoordTouchToBitmap(0, 0, true); + PointF bottomRight = transformCoordTouchToBitmap(viewWidth, viewHeight, true); + + float w = getDrawable().getIntrinsicWidth(); + float h = getDrawable().getIntrinsicHeight(); + return new RectF(topLeft.x / w, topLeft.y / h, bottomRight.x / w, bottomRight.y / h); + } + + /** + * Save the current matrix and view dimensions + * in the prevMatrix and prevView variables. + */ + private void savePreviousImageValues() { + if (matrix != null && viewHeight != 0 && viewWidth != 0) { + matrix.getValues(m); + prevMatrix.setValues(m); + prevMatchViewHeight = matchViewHeight; + prevMatchViewWidth = matchViewWidth; + prevViewHeight = viewHeight; + prevViewWidth = viewWidth; + } + } + + @Override + public Parcelable onSaveInstanceState() { + Bundle bundle = new Bundle(); + bundle.putParcelable("instanceState", super.onSaveInstanceState()); + bundle.putFloat("saveScale", normalizedScale); + bundle.putFloat("matchViewHeight", matchViewHeight); + bundle.putFloat("matchViewWidth", matchViewWidth); + bundle.putInt("viewWidth", viewWidth); + bundle.putInt("viewHeight", viewHeight); + matrix.getValues(m); + bundle.putFloatArray("matrix", m); + bundle.putBoolean("imageRendered", imageRenderedAtLeastOnce); + return bundle; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + if (state instanceof Bundle) { + Bundle bundle = (Bundle) state; + normalizedScale = bundle.getFloat("saveScale"); + m = bundle.getFloatArray("matrix"); + prevMatrix.setValues(m); + prevMatchViewHeight = bundle.getFloat("matchViewHeight"); + prevMatchViewWidth = bundle.getFloat("matchViewWidth"); + prevViewHeight = bundle.getInt("viewHeight"); + prevViewWidth = bundle.getInt("viewWidth"); + imageRenderedAtLeastOnce = bundle.getBoolean("imageRendered"); + super.onRestoreInstanceState(bundle.getParcelable("instanceState")); + return; + } + + super.onRestoreInstanceState(state); + } + + @Override + protected void onDraw(Canvas canvas) { + onDrawReady = true; + imageRenderedAtLeastOnce = true; + if (delayedZoomVariables != null) { + setZoom(delayedZoomVariables.scale, delayedZoomVariables.focusX, delayedZoomVariables.focusY, delayedZoomVariables.scaleType); + delayedZoomVariables = null; + } + super.onDraw(canvas); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + savePreviousImageValues(); + } + + /** + * Get the max zoom multiplier. + * + * @return max zoom multiplier. + */ + public float getMaxZoom() { + return maxScale; + } + + /** + * Set the max zoom multiplier. Default value: 3. + * + * @param max max zoom multiplier. + */ + public void setMaxZoom(float max) { + maxScale = max; + superMaxScale = SUPER_MAX_MULTIPLIER * maxScale; + } + + /** + * Get the min zoom multiplier. + * + * @return min zoom multiplier. + */ + public float getMinZoom() { + return minScale; + } + + /** + * Get the current zoom. This is the zoom relative to the initial + * scale, not the original resource. + * + * @return current zoom multiplier. + */ + public float getCurrentZoom() { + return normalizedScale; + } + + /** + * Set the min zoom multiplier. Default value: 1. + * + * @param min min zoom multiplier. + */ + public void setMinZoom(float min) { + minScale = min; + superMinScale = SUPER_MIN_MULTIPLIER * minScale; + } + + /** + * Reset zoom and translation to initial state. + */ + public void resetZoom() { + normalizedScale = 1; + fitImageToView(); + } + + /** + * Set zoom to the specified scale. Image will be centered by default. + * + * @param scale + */ + public void setZoom(float scale) { + setZoom(scale, 0.5f, 0.5f); + } + + /** + * Set zoom to the specified scale. Image will be centered around the point + * (focusX, focusY). These floats range from 0 to 1 and denote the focus point + * as a fraction from the left and top of the view. For example, the top left + * corner of the image would be (0, 0). And the bottom right corner would be (1, 1). + * + * @param scale + * @param focusX + * @param focusY + */ + public void setZoom(float scale, float focusX, float focusY) { + setZoom(scale, focusX, focusY, mScaleType); + } + + /** + * Set zoom to the specified scale. Image will be centered around the point + * (focusX, focusY). These floats range from 0 to 1 and denote the focus point + * as a fraction from the left and top of the view. For example, the top left + * corner of the image would be (0, 0). And the bottom right corner would be (1, 1). + * + * @param scale + * @param focusX + * @param focusY + * @param scaleType + */ + public void setZoom(float scale, float focusX, float focusY, ScaleType scaleType) { + // + // setZoom can be called before the image is on the screen, but at this point, + // image and view sizes have not yet been calculated in onMeasure. Thus, we should + // delay calling setZoom until the view has been measured. + // + if (!onDrawReady) { + delayedZoomVariables = new ZoomVariables(scale, focusX, focusY, scaleType); + return; + } + + if (scaleType != mScaleType) { + setScaleType(scaleType); + } + resetZoom(); + scaleImage(scale, viewWidth / 2, viewHeight / 2, true); + matrix.getValues(m); + m[Matrix.MTRANS_X] = -((focusX * getImageWidth()) - (viewWidth * 0.5f)); + m[Matrix.MTRANS_Y] = -((focusY * getImageHeight()) - (viewHeight * 0.5f)); + matrix.setValues(m); + fixTrans(); + setImageMatrix(matrix); + } + + /** + * Set zoom parameters equal to another TouchImageView. Including scale, position, + * and ScaleType. + * + * @param img + */ + public void setZoom(TouchImageView img) { + PointF center = img.getScrollPosition(); + setZoom(img.getCurrentZoom(), center.x, center.y, img.getScaleType()); + } + + /** + * Return the point at the center of the zoomed image. The PointF coordinates range + * in value between 0 and 1 and the focus point is denoted as a fraction from the left + * and top of the view. For example, the top left corner of the image would be (0, 0). + * And the bottom right corner would be (1, 1). + * + * @return PointF representing the scroll position of the zoomed image. + */ + public PointF getScrollPosition() { + Drawable drawable = getDrawable(); + if (drawable == null) { + return null; + } + int drawableWidth = drawable.getIntrinsicWidth(); + int drawableHeight = drawable.getIntrinsicHeight(); + + PointF point = transformCoordTouchToBitmap(viewWidth / 2, viewHeight / 2, true); + point.x /= drawableWidth; + point.y /= drawableHeight; + return point; + } + + /** + * Set the focus point of the zoomed image. The focus points are denoted as a fraction from the + * left and top of the view. The focus points can range in value between 0 and 1. + * + * @param focusX + * @param focusY + */ + public void setScrollPosition(float focusX, float focusY) { + setZoom(normalizedScale, focusX, focusY); + } + + /** + * Performs boundary checking and fixes the image matrix if it + * is out of bounds. + */ + private void fixTrans() { + matrix.getValues(m); + float transX = m[Matrix.MTRANS_X]; + float transY = m[Matrix.MTRANS_Y]; + + float fixTransX = getFixTrans(transX, viewWidth, getImageWidth()); + float fixTransY = getFixTrans(transY, viewHeight, getImageHeight()); + + if (fixTransX != 0 || fixTransY != 0) { + matrix.postTranslate(fixTransX, fixTransY); + } + } + + /** + * When transitioning from zooming from focus to zoom from center (or vice versa) + * the image can become unaligned within the view. This is apparent when zooming + * quickly. When the content size is less than the view size, the content will often + * be centered incorrectly within the view. fixScaleTrans first calls fixTrans() and + * then makes sure the image is centered correctly within the view. + */ + private void fixScaleTrans() { + fixTrans(); + matrix.getValues(m); + if (getImageWidth() < viewWidth) { + m[Matrix.MTRANS_X] = (viewWidth - getImageWidth()) / 2; + } + + if (getImageHeight() < viewHeight) { + m[Matrix.MTRANS_Y] = (viewHeight - getImageHeight()) / 2; + } + matrix.setValues(m); + } + + private float getFixTrans(float trans, float viewSize, float contentSize) { + float minTrans, maxTrans; + + if (contentSize <= viewSize) { + minTrans = 0; + maxTrans = viewSize - contentSize; + + } else { + minTrans = viewSize - contentSize; + maxTrans = 0; + } + + if (trans < minTrans) + return -trans + minTrans; + if (trans > maxTrans) + return -trans + maxTrans; + return 0; + } + + private float getFixDragTrans(float delta, float viewSize, float contentSize) { + if (contentSize <= viewSize) { + return 0; + } + return delta; + } + + private float getImageWidth() { + return matchViewWidth * normalizedScale; + } + + private float getImageHeight() { + return matchViewHeight * normalizedScale; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + Drawable drawable = getDrawable(); + if (drawable == null || drawable.getIntrinsicWidth() == 0 || drawable.getIntrinsicHeight() == 0) { + setMeasuredDimension(0, 0); + return; + } + + int drawableWidth = drawable.getIntrinsicWidth(); + int drawableHeight = drawable.getIntrinsicHeight(); + int widthSize = MeasureSpec.getSize(widthMeasureSpec); + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + int heightSize = MeasureSpec.getSize(heightMeasureSpec); + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + viewWidth = setViewSize(widthMode, widthSize, drawableWidth); + viewHeight = setViewSize(heightMode, heightSize, drawableHeight); + + // + // Set view dimensions + // + setMeasuredDimension(viewWidth, viewHeight); + + // + // Fit content within view + // + fitImageToView(); + } + + /** + * If the normalizedScale is equal to 1, then the image is made to fit the screen. Otherwise, + * it is made to fit the screen according to the dimensions of the previous image matrix. This + * allows the image to maintain its zoom after rotation. + */ + private void fitImageToView() { + Drawable drawable = getDrawable(); + if (drawable == null || drawable.getIntrinsicWidth() == 0 || drawable.getIntrinsicHeight() == 0) { + return; + } + if (matrix == null || prevMatrix == null) { + return; + } + + int drawableWidth = drawable.getIntrinsicWidth(); + int drawableHeight = drawable.getIntrinsicHeight(); + +// TLog.log("imageView", "viewWidth=" + viewWidth + ":viewHeight" + viewHeight + "drawableWidth=" + drawableWidth + ":drawableHeight" + drawableHeight); + + // + // Scale image for view + // + float scaleX = (float) viewWidth / drawableWidth; + float scaleY = scaleX; + + // + // Center the image + // + float redundantXSpace = viewWidth - (scaleX * drawableWidth); + float redundantYSpace = viewHeight - (scaleY * drawableHeight); + matchViewWidth = viewWidth - redundantXSpace; + matchViewHeight = viewHeight - redundantYSpace; + if (!isZoomed() && !imageRenderedAtLeastOnce) { + // + // Stretch and center image to fit view + // + matrix.setScale(scaleX, scaleY); + if (matchViewHeight > viewHeight) { + matrix.postTranslate(0, 0); + } else { + matrix.postTranslate(redundantXSpace / 2, redundantYSpace / 2); + } + + normalizedScale = 1; + + } else { + // + // These values should never be 0 or we will set viewWidth and viewHeight + // to NaN in translateMatrixAfterRotate. To avoid this, call savePreviousImageValues + // to set them equal to the current values. + // + if (prevMatchViewWidth == 0 || prevMatchViewHeight == 0) { + savePreviousImageValues(); + } + + prevMatrix.getValues(m); + + // + // Rescale Matrix after rotation + // + m[Matrix.MSCALE_X] = matchViewWidth / drawableWidth * normalizedScale; + m[Matrix.MSCALE_Y] = matchViewHeight / drawableHeight * normalizedScale; + + // + // TransX and TransY from previous matrix + // + float transX = m[Matrix.MTRANS_X]; + float transY = m[Matrix.MTRANS_Y]; + + // + // Width + // + float prevActualWidth = prevMatchViewWidth * normalizedScale; + float actualWidth = getImageWidth(); + translateMatrixAfterRotate(Matrix.MTRANS_X, transX, prevActualWidth, actualWidth, prevViewWidth, viewWidth, drawableWidth); + + // + // Height + // + float prevActualHeight = prevMatchViewHeight * normalizedScale; + float actualHeight = getImageHeight(); + translateMatrixAfterRotate(Matrix.MTRANS_Y, transY, prevActualHeight, actualHeight, prevViewHeight, viewHeight, drawableHeight); + + // + // Set the matrix to the adjusted scale and translate values. + // + matrix.setValues(m); + } + fixTrans(); + setImageMatrix(matrix); + } + + /** + * Set view dimensions based on layout params + * + * @param mode + * @param size + * @param drawableWidth + * @return + */ + private int setViewSize(int mode, int size, int drawableWidth) { + int viewSize; + switch (mode) { + case MeasureSpec.EXACTLY: + viewSize = size; + break; + + case MeasureSpec.AT_MOST: + viewSize = Math.min(drawableWidth, size); + break; + + case MeasureSpec.UNSPECIFIED: + viewSize = drawableWidth; + break; + + default: + viewSize = size; + break; + } + return viewSize; + } + + /** + * After rotating, the matrix needs to be translated. This function finds the area of image + * which was previously centered and adjusts translations so that is again the center, post-rotation. + * + * @param axis Matrix.MTRANS_X or Matrix.MTRANS_Y + * @param trans the value of trans in that axis before the rotation + * @param prevImageSize the width/height of the image before the rotation + * @param imageSize width/height of the image after rotation + * @param prevViewSize width/height of view before rotation + * @param viewSize width/height of view after rotation + * @param drawableSize width/height of drawable + */ + private void translateMatrixAfterRotate(int axis, float trans, float prevImageSize, float imageSize, int prevViewSize, int viewSize, int drawableSize) { + if (imageSize < viewSize) { + // + // The width/height of image is less than the view's width/height. Center it. + // + m[axis] = (viewSize - (drawableSize * m[Matrix.MSCALE_X])) * 0.5f; + + } else if (trans > 0) { + // + // The image is larger than the view, but was not before rotation. Center it. + // + m[axis] = -((imageSize - viewSize) * 0.5f); + + } else { + // + // Find the area of the image which was previously centered in the view. Determine its distance + // from the left/top side of the view as a fraction of the entire image's width/height. Use that percentage + // to calculate the trans in the new view width/height. + // + float percentage = (Math.abs(trans) + (0.5f * prevViewSize)) / prevImageSize; + m[axis] = -((percentage * imageSize) - (viewSize * 0.5f)); + } + } + + private void setState(State state) { + this.state = state; + } + + public boolean canScrollHorizontallyFroyo(int direction) { + return canScrollHorizontally(direction); + } + + @Override + public boolean canScrollHorizontally(int direction) { + matrix.getValues(m); + float x = m[Matrix.MTRANS_X]; + + if (getImageWidth() < viewWidth) { + return false; + + } else if (x >= -1 && direction < 0) { + return false; + + } else if (Math.abs(x) + viewWidth + 1 >= getImageWidth() && direction > 0) { + return false; + } + + return true; + } + + /** + * Gesture Listener detects a single click or long click and passes that on + * to the view's listener. + * + * @author Ortiz + */ + private class GestureListener extends GestureDetector.SimpleOnGestureListener { + + @Override + public boolean onSingleTapConfirmed(MotionEvent e) { + if (doubleTapListener != null) { + return doubleTapListener.onSingleTapConfirmed(e); + } + return performClick(); + } + + @Override + public void onLongPress(MotionEvent e) { + performLongClick(); + } + + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + if (fling != null) { + // + // If a previous fling is still active, it should be cancelled so that two flings + // are not run simultaenously. + // + fling.cancelFling(); + } + fling = new Fling((int) velocityX, (int) velocityY); + compatPostOnAnimation(fling); + return super.onFling(e1, e2, velocityX, velocityY); + } + + @Override + public boolean onDoubleTap(MotionEvent e) { + boolean consumed = false; + if (doubleTapListener != null) { + consumed = doubleTapListener.onDoubleTap(e); + } + if (state == State.NONE) { + float targetZoom = (normalizedScale == minScale) ? maxScale : minScale; + DoubleTapZoom doubleTap = new DoubleTapZoom(targetZoom, e.getX(), e.getY(), false); + compatPostOnAnimation(doubleTap); + consumed = true; + } + return consumed; + } + + @Override + public boolean onDoubleTapEvent(MotionEvent e) { + if (doubleTapListener != null) { + return doubleTapListener.onDoubleTapEvent(e); + } + return false; + } + } + + public interface OnTouchImageViewListener { + public void onMove(); + } + + + + /** + * Responsible for all touch events. Handles the heavy lifting of drag and also sends + * touch events to Scale Detector and Gesture Detector. + * + * @author Ortiz + */ + private class PrivateOnTouchListener implements OnTouchListener { + + // + // Remember last point position for dragging + // + private PointF last = new PointF(); + + @Override + public boolean onTouch(View v, MotionEvent event) { + mScaleDetector.onTouchEvent(event); + mGestureDetector.onTouchEvent(event); + PointF curr = new PointF(event.getX(), event.getY()); + + if (state == State.NONE || state == State.DRAG || state == State.FLING) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + last.set(curr); + if (fling != null) + fling.cancelFling(); + setState(State.DRAG); + break; + + case MotionEvent.ACTION_MOVE: + if (state == State.DRAG) { + float deltaX = curr.x - last.x; + float deltaY = curr.y - last.y; + + float fixTransX = getFixDragTrans(deltaX, viewWidth, getImageWidth()); + float fixTransY = getFixDragTrans(deltaY, viewHeight, getImageHeight()); + matrix.postTranslate(fixTransX, fixTransY); + fixTrans(); + last.set(curr.x, curr.y); + } + break; + + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_POINTER_UP: + setState(State.NONE); + break; + } + } + + setImageMatrix(matrix); + + // + // User-defined OnTouchListener + // + if (userTouchListener != null) { + userTouchListener.onTouch(v, event); + } + + // + // OnTouchImageViewListener is set: TouchImageView dragged by user. + // + if (touchImageViewListener != null) { + touchImageViewListener.onMove(); + } + + // + // indicate event was handled + // + return true; + } + } + + /** + * ScaleListener detects user two finger scaling and scales image. + * + * @author Ortiz + */ + private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { + @Override + public boolean onScaleBegin(ScaleGestureDetector detector) { + setState(State.ZOOM); + return true; + } + + @Override + public boolean onScale(ScaleGestureDetector detector) { + scaleImage(detector.getScaleFactor(), detector.getFocusX(), detector.getFocusY(), true); + + // + // OnTouchImageViewListener is set: TouchImageView pinch zoomed by user. + // + if (touchImageViewListener != null) { + touchImageViewListener.onMove(); + } + return true; + } + + @Override + public void onScaleEnd(ScaleGestureDetector detector) { + super.onScaleEnd(detector); + setState(State.NONE); + boolean animateToZoomBoundary = false; + float targetZoom = normalizedScale; + if (normalizedScale > maxScale) { + targetZoom = maxScale; + animateToZoomBoundary = true; + + } else if (normalizedScale < minScale) { + targetZoom = minScale; + animateToZoomBoundary = true; + } + + if (animateToZoomBoundary) { + DoubleTapZoom doubleTap = new DoubleTapZoom(targetZoom, viewWidth / 2, viewHeight / 2, true); + compatPostOnAnimation(doubleTap); + } + } + } + + private void scaleImage(double deltaScale, float focusX, float focusY, boolean stretchImageToSuper) { + + float lowerScale, upperScale; + if (stretchImageToSuper) { + lowerScale = superMinScale; + upperScale = superMaxScale; + + } else { + lowerScale = minScale; + upperScale = maxScale; + } + + float origScale = normalizedScale; + normalizedScale *= deltaScale; + if (normalizedScale > upperScale) { + normalizedScale = upperScale; + deltaScale = upperScale / origScale; + } else if (normalizedScale < lowerScale) { + normalizedScale = lowerScale; + deltaScale = lowerScale / origScale; + } + + matrix.postScale((float) deltaScale, (float) deltaScale, focusX, focusY); + fixScaleTrans(); + } + + /** + * DoubleTapZoom calls a series of runnables which apply + * an animated zoom in/out graphic to the image. + * + * @author Ortiz + */ + private class DoubleTapZoom implements Runnable { + + private long startTime; + private static final float ZOOM_TIME = 500; + private float startZoom, targetZoom; + private float bitmapX, bitmapY; + private boolean stretchImageToSuper; + private AccelerateDecelerateInterpolator interpolator = new AccelerateDecelerateInterpolator(); + private PointF startTouch; + private PointF endTouch; + + DoubleTapZoom(float targetZoom, float focusX, float focusY, boolean stretchImageToSuper) { + setState(State.ANIMATE_ZOOM); + startTime = System.currentTimeMillis(); + this.startZoom = normalizedScale; + this.targetZoom = targetZoom; + this.stretchImageToSuper = stretchImageToSuper; + PointF bitmapPoint = transformCoordTouchToBitmap(focusX, focusY, false); + this.bitmapX = bitmapPoint.x; + this.bitmapY = bitmapPoint.y; + + // + // Used for translating image during scaling + // + startTouch = transformCoordBitmapToTouch(bitmapX, bitmapY); + endTouch = new PointF(viewWidth / 2, viewHeight / 2); + } + + @Override + public void run() { + float t = interpolate(); + double deltaScale = calculateDeltaScale(t); + scaleImage(deltaScale, bitmapX, bitmapY, stretchImageToSuper); + translateImageToCenterTouchPosition(t); + fixScaleTrans(); + setImageMatrix(matrix); + + // + // OnTouchImageViewListener is set: double tap runnable updates listener + // with every frame. + // + if (touchImageViewListener != null) { + touchImageViewListener.onMove(); + } + + if (t < 1f) { + // + // We haven't finished zooming + // + compatPostOnAnimation(this); + + } else { + // + // Finished zooming + // + setState(State.NONE); + } + } + + /** + * Interpolate between where the image should start and end in order to translate + * the image so that the point that is touched is what ends up centered at the end + * of the zoom. + * + * @param t + */ + private void translateImageToCenterTouchPosition(float t) { + float targetX = startTouch.x + t * (endTouch.x - startTouch.x); + float targetY = startTouch.y + t * (endTouch.y - startTouch.y); + PointF curr = transformCoordBitmapToTouch(bitmapX, bitmapY); + matrix.postTranslate(targetX - curr.x, targetY - curr.y); + } + + /** + * Use interpolator to get t + * + * @return + */ + private float interpolate() { + long currTime = System.currentTimeMillis(); + float elapsed = (currTime - startTime) / ZOOM_TIME; + elapsed = Math.min(1f, elapsed); + return interpolator.getInterpolation(elapsed); + } + + /** + * Interpolate the current targeted zoom and get the delta + * from the current zoom. + * + * @param t + * @return + */ + private double calculateDeltaScale(float t) { + double zoom = startZoom + t * (targetZoom - startZoom); + return zoom / normalizedScale; + } + } + + /** + * This function will transform the coordinates in the touch event to the coordinate + * system of the drawable that the imageview contain + * + * @param x x-coordinate of touch event + * @param y y-coordinate of touch event + * @param clipToBitmap Touch event may occur within view, but outside image content. True, to clip return value + * to the bounds of the bitmap size. + * @return Coordinates of the point touched, in the coordinate system of the original drawable. + */ + private PointF transformCoordTouchToBitmap(float x, float y, boolean clipToBitmap) { + matrix.getValues(m); + float origW = getDrawable().getIntrinsicWidth(); + float origH = getDrawable().getIntrinsicHeight(); + float transX = m[Matrix.MTRANS_X]; + float transY = m[Matrix.MTRANS_Y]; + float finalX = ((x - transX) * origW) / getImageWidth(); + float finalY = ((y - transY) * origH) / getImageHeight(); + + if (clipToBitmap) { + finalX = Math.min(Math.max(finalX, 0), origW); + finalY = Math.min(Math.max(finalY, 0), origH); + } + + return new PointF(finalX, finalY); + } + + /** + * Inverse of transformCoordTouchToBitmap. This function will transform the coordinates in the + * drawable's coordinate system to the view's coordinate system. + * + * @param bx x-coordinate in original bitmap coordinate system + * @param by y-coordinate in original bitmap coordinate system + * @return Coordinates of the point in the view's coordinate system. + */ + private PointF transformCoordBitmapToTouch(float bx, float by) { + matrix.getValues(m); + float origW = getDrawable().getIntrinsicWidth(); + float origH = getDrawable().getIntrinsicHeight(); + float px = bx / origW; + float py = by / origH; + float finalX = m[Matrix.MTRANS_X] + getImageWidth() * px; + float finalY = m[Matrix.MTRANS_Y] + getImageHeight() * py; + return new PointF(finalX, finalY); + } + + /** + * Fling launches sequential runnables which apply + * the fling graphic to the image. The values for the translation + * are interpolated by the Scroller. + * + * @author Ortiz + */ + private class Fling implements Runnable { + + CompatScroller scroller; + int currX, currY; + + Fling(int velocityX, int velocityY) { + setState(State.FLING); + scroller = new CompatScroller(context); + matrix.getValues(m); + + int startX = (int) m[Matrix.MTRANS_X]; + int startY = (int) m[Matrix.MTRANS_Y]; + int minX, maxX, minY, maxY; + + if (getImageWidth() > viewWidth) { + minX = viewWidth - (int) getImageWidth(); + maxX = 0; + + } else { + minX = maxX = startX; + } + + if (getImageHeight() > viewHeight) { + minY = viewHeight - (int) getImageHeight(); + maxY = 0; + + } else { + minY = maxY = startY; + } + + scroller.fling(startX, startY, (int) velocityX, (int) velocityY, minX, + maxX, minY, maxY); + currX = startX; + currY = startY; + } + + public void cancelFling() { + if (scroller != null) { + setState(State.NONE); + scroller.forceFinished(true); + } + } + + @Override + public void run() { + + // + // OnTouchImageViewListener is set: TouchImageView listener has been flung by user. + // Listener runnable updated with each frame of fling animation. + // + if (touchImageViewListener != null) { + touchImageViewListener.onMove(); + } + + if (scroller.isFinished()) { + scroller = null; + return; + } + + if (scroller.computeScrollOffset()) { + int newX = scroller.getCurrX(); + int newY = scroller.getCurrY(); + int transX = newX - currX; + int transY = newY - currY; + currX = newX; + currY = newY; + matrix.postTranslate(transX, transY); + fixTrans(); + setImageMatrix(matrix); + compatPostOnAnimation(this); + } + } + } + + @TargetApi(VERSION_CODES.GINGERBREAD) + private class CompatScroller { + Scroller scroller; + OverScroller overScroller; + boolean isPreGingerbread; + + public CompatScroller(Context context) { + if (VERSION.SDK_INT < VERSION_CODES.GINGERBREAD) { + isPreGingerbread = true; + scroller = new Scroller(context); + + } else { + isPreGingerbread = false; + overScroller = new OverScroller(context); + } + } + + public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY) { + if (isPreGingerbread) { + scroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY); + } else { + overScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY); + } + } + + public void forceFinished(boolean finished) { + if (isPreGingerbread) { + scroller.forceFinished(finished); + } else { + overScroller.forceFinished(finished); + } + } + + public boolean isFinished() { + if (isPreGingerbread) { + return scroller.isFinished(); + } else { + return overScroller.isFinished(); + } + } + + public boolean computeScrollOffset() { + if (isPreGingerbread) { + return scroller.computeScrollOffset(); + } else { + overScroller.computeScrollOffset(); + return overScroller.computeScrollOffset(); + } + } + + public int getCurrX() { + if (isPreGingerbread) { + return scroller.getCurrX(); + } else { + return overScroller.getCurrX(); + } + } + + public int getCurrY() { + if (isPreGingerbread) { + return scroller.getCurrY(); + } else { + return overScroller.getCurrY(); + } + } + } + + @TargetApi(VERSION_CODES.JELLY_BEAN) + private void compatPostOnAnimation(Runnable runnable) { + if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) { + postOnAnimation(runnable); + + } else { + postDelayed(runnable, 1000 / 60); + } + } + + private class ZoomVariables { + public float scale; + public float focusX; + public float focusY; + public ScaleType scaleType; + + public ZoomVariables(float scale, float focusX, float focusY, ScaleType scaleType) { + this.scale = scale; + this.focusX = focusX; + this.focusY = focusY; + this.scaleType = scaleType; + } + } + + private void printMatrixInfo() { + float[] n = new float[9]; + matrix.getValues(n); + Log.d(DEBUG, "Scale: " + n[Matrix.MSCALE_X] + " TransX: " + n[Matrix.MTRANS_X] + " TransY: " + n[Matrix.MTRANS_Y]); + } + + +} \ No newline at end of file diff --git a/app/src/main/java/net/oschina/app/widget/am.java b/app/src/main/java/net/oschina/app/widget/am.java index 64795426e34b632a31ac238aa46301da6df53caa..9ffe851edbdc6b44c8e8e1be07abe7f7616ceb0d 100644 --- a/app/src/main/java/net/oschina/app/widget/am.java +++ b/app/src/main/java/net/oschina/app/widget/am.java @@ -91,18 +91,18 @@ public abstract class am extends ReplacementSpan { e = i2; } Drawable drawable = resources - .getDrawable(R.drawable.timeline_card_small_button); + .getDrawable(R.mipmap.timeline_card_small_button); // a1.b(R.drawable.timeline_card_small_button); drawable.setBounds(0, 0, e, f); l[0] = drawable; Drawable drawable1 = resources - .getDrawable(R.drawable.timeline_card_small_button_highlighted); + .getDrawable(R.mipmap.timeline_card_small_button_highlighted); // a1.b(R.drawable.timeline_card_small_button_highlighted); drawable1.setBounds(0, 0, e, f); l[1] = drawable1; if (h == null) { h = resources - .getDrawable(R.drawable.timeline_card_small_placeholder); + .getDrawable(R.mipmap.timeline_card_small_placeholder); // h = a1.b(R.drawable.timeline_card_small_placeholder); } h.setBounds(0, 0, i, j); diff --git a/app/src/main/java/net/oschina/app/widget/togglebutton/ToggleButton.java b/app/src/main/java/net/oschina/app/widget/togglebutton/ToggleButton.java deleted file mode 100644 index 27027f6b22facab97c58009a8da8680d31288be8..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/widget/togglebutton/ToggleButton.java +++ /dev/null @@ -1,267 +0,0 @@ -package net.oschina.app.widget.togglebutton; - -import net.oschina.app.R; -import net.oschina.app.widget.tooglebutton.rebound.SimpleSpringListener; -import net.oschina.app.widget.tooglebutton.rebound.Spring; -import net.oschina.app.widget.tooglebutton.rebound.SpringConfig; -import net.oschina.app.widget.tooglebutton.rebound.SpringSystem; -import net.oschina.app.widget.tooglebutton.rebound.SpringUtil; -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Paint.Cap; -import android.graphics.Paint.Style; -import android.graphics.RectF; -import android.util.AttributeSet; -import android.view.View; - -/** - * @author ThinkPad - * - */ -public class ToggleButton extends View { - private SpringSystem springSystem; - private Spring spring ; - /** */ - private float radius; - /** 开启颜色*/ - private int onColor = Color.parseColor("#4ebb7f"); - /** 关闭颜色*/ - private int offBorderColor = Color.parseColor("#dadbda"); - /** 灰色带颜色*/ - private int offColor = Color.parseColor("#ffffff"); - /** 手柄颜色*/ - private int spotColor = Color.parseColor("#ffffff"); - /** 边框颜色*/ - private int borderColor = offBorderColor; - /** 画笔*/ - private Paint paint ; - /** 开关状态*/ - private boolean toggleOn = false; - /** 边框大小*/ - private int borderWidth = 2; - /** 垂直中心*/ - private float centerY; - /** 按钮的开始和结束位置*/ - private float startX, endX; - /** 手柄X位置的最小和最大值*/ - private float spotMinX, spotMaxX; - /**手柄大小 */ - private int spotSize ; - /** 手柄X位置*/ - private float spotX; - /** 关闭时内部灰色带高度*/ - private float offLineWidth; - /** */ - private RectF rect = new RectF(); - - private OnToggleChanged listener; - - private ToggleButton(Context context) { - super(context); - } - public ToggleButton(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - setup(attrs); - } - public ToggleButton(Context context, AttributeSet attrs) { - super(context, attrs); - setup(attrs); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - spring.removeListener(springListener); - } - - public void onAttachedToWindow() { - super.onAttachedToWindow(); - spring.addListener(springListener); - } - - public void setup(AttributeSet attrs) { - paint = new Paint(Paint.ANTI_ALIAS_FLAG); - paint.setStyle(Style.FILL); - paint.setStrokeCap(Cap.ROUND); - - springSystem = SpringSystem.create(); - spring = springSystem.createSpring(); - spring.setSpringConfig(SpringConfig.fromOrigamiTensionAndFriction(50, 7)); - - this.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View arg0) { - toggle(); - } - }); - - TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.ToggleButton); - offBorderColor = typedArray.getColor(R.styleable.ToggleButton_offBorderColor, offBorderColor); - onColor = typedArray.getColor(R.styleable.ToggleButton_onColor, onColor); - spotColor = typedArray.getColor(R.styleable.ToggleButton_spotColor, spotColor); - offColor = typedArray.getColor(R.styleable.ToggleButton_offColor, offColor); - borderWidth = typedArray.getDimensionPixelSize(R.styleable.ToggleButton_borderWidth, borderWidth); - typedArray.recycle(); - } - - public void toggle() { - toggleOn = !toggleOn; - spring.setEndValue(toggleOn ? 1 : 0); - if(listener != null){ - listener.onToggle(toggleOn); - } - } - - public void toggleOn() { - setToggleOn(); - if(listener != null){ - listener.onToggle(toggleOn); - } - } - - public void toggleOff() { - setToggleOff(); - if(listener != null){ - listener.onToggle(toggleOn); - } - } - - /** - * 设置显示成打开样式,不会触发toggle事件 - */ - public void setToggleOn() { - toggleOn = true; - spring.setEndValue(toggleOn ? 1 : 0); - } - - /** - * 设置显示成关闭样式,不会触发toggle事件 - */ - public void setToggleOff() { - toggleOn = false; - spring.setEndValue(toggleOn ? 1 : 0); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, - int bottom) { - super.onLayout(changed, left, top, right, bottom); - - final int width = getWidth(); - final int height = getHeight(); - radius = Math.min(width, height) * 0.5f; - centerY = radius; - startX = radius; - endX = width - radius; - spotMinX = startX + borderWidth; - spotMaxX = endX - borderWidth; - spotSize = height - 4 * borderWidth; - spotX = spotMinX; - offLineWidth = 0; - } - - - SimpleSpringListener springListener = new SimpleSpringListener(){ - @Override - public void onSpringUpdate(Spring spring) { - final double value = spring.getCurrentValue(); - - final float mapToggleX = (float) SpringUtil.mapValueFromRangeToRange(value, 0, 1, spotMinX, spotMaxX); - spotX = mapToggleX; - - float mapOffLineWidth = (float) SpringUtil.mapValueFromRangeToRange(1 - value, 0, 1, 10, spotSize); - - offLineWidth = mapOffLineWidth; - - final int fb = Color.blue(onColor); - final int fr = Color.red(onColor); - final int fg = Color.green(onColor); - - final int tb = Color.blue(offBorderColor); - final int tr = Color.red(offBorderColor); - final int tg = Color.green(offBorderColor); - - int sb = (int) SpringUtil.mapValueFromRangeToRange(1 - value, 0, 1, fb, tb); - int sr = (int) SpringUtil.mapValueFromRangeToRange(1 - value, 0, 1, fr, tr); - int sg = (int) SpringUtil.mapValueFromRangeToRange(1 - value, 0, 1, fg, tg); - - sb = SpringUtil.clamp(sb, 0, 255); - sr = SpringUtil.clamp(sr, 0, 255); - sg = SpringUtil.clamp(sg, 0, 255); - - borderColor = Color.rgb(sr, sg, sb); - - postInvalidate(); - } - }; - - - @Override - public void draw(Canvas canvas) { - - /* - final int height = getHeight(); - //绘制背景(边框) - paint.setStrokeWidth(height); - paint.setColor(borderColor); - canvas.drawLine(startX, centerY, endX, centerY, paint); - //绘制灰色带 - if(offLineWidth > 0){ - paint.setStrokeWidth(offLineWidth); - paint.setColor(offColor); - canvas.drawLine(spotX, centerY, endX, centerY, paint); - } - //spot的边框 - paint.setStrokeWidth(height); - paint.setColor(borderColor); - canvas.drawLine(spotX - 1, centerY, spotX + 1.1f, centerY, paint); - //spot - paint.setStrokeWidth(spotSize); - paint.setColor(spotColor); - canvas.drawLine(spotX, centerY, spotX + 0.1f, centerY, paint); - */ - - - // - rect.set(0, 0, getWidth(), getHeight()); - paint.setColor(borderColor); - canvas.drawRoundRect(rect, radius, radius, paint); - - if(offLineWidth > 0){ - final float cy = offLineWidth * 0.5f; - rect.set(spotX - cy, centerY - cy, endX + cy, centerY + cy); - paint.setColor(offColor); - canvas.drawRoundRect(rect, cy, cy, paint); - } - - rect.set(spotX - 1 - radius, centerY - radius, spotX + 1.1f + radius, centerY + radius); - paint.setColor(borderColor); - canvas.drawRoundRect(rect, radius, radius, paint); - - final float spotR = spotSize * 0.5f; - rect.set(spotX - spotR, centerY - spotR, spotX + spotR, centerY + spotR); - paint.setColor(spotColor); - canvas.drawRoundRect(rect, spotR, spotR, paint); - - } - - - /** - * @author ThinkPad - * - */ - public interface OnToggleChanged{ - /** - * @param on - */ - public void onToggle(boolean on); - } - - - public void setOnToggleChanged(OnToggleChanged onToggleChanged) { - listener = onToggleChanged; - } -} diff --git a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/AndroidSpringLooperFactory.java b/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/AndroidSpringLooperFactory.java deleted file mode 100644 index 559944baa05583a7ee05e261613c106590cb380f..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/AndroidSpringLooperFactory.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2013, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -package net.oschina.app.widget.tooglebutton.rebound; - -import android.annotation.TargetApi; -import android.os.Build; -import android.os.Handler; -import android.os.SystemClock; -import android.view.Choreographer; - -/** - * Android version of the spring looper that uses the most appropriate frame callback mechanism - * available. It uses Android's {@link Choreographer} when available, otherwise it uses a - * {@link Handler}. - */ -abstract class AndroidSpringLooperFactory { - - /** - * Create an Android {@link com.facebook.rebound.SpringLooper} for the detected Android platform. - * @return a SpringLooper - */ - public static SpringLooper createSpringLooper() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - return ChoreographerAndroidSpringLooper.create(); - } else { - return LegacyAndroidSpringLooper.create(); - } - } - - /** - * The base implementation of the Android spring looper, using a {@link Handler} for the - * frame callbacks. - */ - private static class LegacyAndroidSpringLooper extends SpringLooper { - - private final Handler mHandler; - private final Runnable mLooperRunnable; - private boolean mStarted; - private long mLastTime; - - /** - * @return an Android spring looper using a new {@link Handler} instance - */ - public static SpringLooper create() { - return new LegacyAndroidSpringLooper(new Handler()); - } - - public LegacyAndroidSpringLooper(Handler handler) { - mHandler = handler; - mLooperRunnable = new Runnable() { - @Override - public void run() { - if (!mStarted || mSpringSystem == null) { - return; - } - long currentTime = SystemClock.uptimeMillis(); - mSpringSystem.loop(currentTime - mLastTime); - mHandler.post(mLooperRunnable); - } - }; - } - - @Override - public void start() { - if (mStarted) { - return; - } - mStarted = true; - mLastTime = SystemClock.uptimeMillis(); - mHandler.removeCallbacks(mLooperRunnable); - mHandler.post(mLooperRunnable); - } - - @Override - public void stop() { - mStarted = false; - mHandler.removeCallbacks(mLooperRunnable); - } - } - - /** - * The Jelly Bean and up implementation of the spring looper that uses Android's - * {@link Choreographer} instead of a {@link Handler} - */ - @TargetApi(Build.VERSION_CODES.JELLY_BEAN) - private static class ChoreographerAndroidSpringLooper extends SpringLooper { - - private final Choreographer mChoreographer; - private final Choreographer.FrameCallback mFrameCallback; - private boolean mStarted; - private long mLastTime; - - /** - * @return an Android spring choreographer using the system {@link Choreographer} - */ - public static ChoreographerAndroidSpringLooper create() { - return new ChoreographerAndroidSpringLooper(Choreographer.getInstance()); - } - - public ChoreographerAndroidSpringLooper(Choreographer choreographer) { - mChoreographer = choreographer; - mFrameCallback = new Choreographer.FrameCallback() { - @Override - public void doFrame(long frameTimeNanos) { - if (!mStarted || mSpringSystem == null) { - return; - } - long currentTime = SystemClock.uptimeMillis(); - mSpringSystem.loop(currentTime - mLastTime); - mLastTime = currentTime; - mChoreographer.postFrameCallback(mFrameCallback); - } - }; - } - - @Override - public void start() { - if (mStarted) { - return; - } - mStarted = true; - mLastTime = SystemClock.uptimeMillis(); - mChoreographer.removeFrameCallback(mFrameCallback); - mChoreographer.postFrameCallback(mFrameCallback); - } - - @Override - public void stop() { - mStarted = false; - mChoreographer.removeFrameCallback(mFrameCallback); - } - } -} \ No newline at end of file diff --git a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/BaseSpringSystem.java b/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/BaseSpringSystem.java deleted file mode 100644 index bde1c9f4294950bd4019cbd402b16a67527cade0..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/BaseSpringSystem.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright (c) 2013, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -package net.oschina.app.widget.tooglebutton.rebound; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArraySet; - -/** - * BaseSpringSystem maintains the set of springs within an Application context. It is responsible for - * Running the spring integration loop and maintains a registry of all the Springs it solves for. - * In addition to listening to physics events on the individual Springs in the system, listeners - * can be added to the BaseSpringSystem itself to provide pre and post integration setup. - */ -public class BaseSpringSystem { - - private final Map mSpringRegistry = new HashMap(); - private final Set mActiveSprings = new CopyOnWriteArraySet(); - private final SpringLooper mSpringLooper; - private final CopyOnWriteArraySet mListeners = new CopyOnWriteArraySet(); - private boolean mIdle = true; - - /** - * create a new BaseSpringSystem - * @param springLooper parameterized springLooper to allow testability of the - * physics loop - */ - public BaseSpringSystem(SpringLooper springLooper) { - if (springLooper == null) { - throw new IllegalArgumentException("springLooper is required"); - } - mSpringLooper = springLooper; - mSpringLooper.setSpringSystem(this); - } - - /** - * check if the system is idle - * @return is the system idle - */ - public boolean getIsIdle() { - return mIdle; - } - - /** - * create a spring with a random uuid for its name. - * @return the spring - */ - public Spring createSpring() { - Spring spring = new Spring(this); - registerSpring(spring); - return spring; - } - - /** - * get a spring by name - * @param id id of the spring to retrieve - * @return Spring with the specified key - */ - public Spring getSpringById(String id) { - if (id == null) { - throw new IllegalArgumentException("id is required"); - } - return mSpringRegistry.get(id); - } - - /** - * return all the springs in the simulator - * @return all the springs - */ - public List getAllSprings() { - Collection collection = mSpringRegistry.values(); - List list; - if (collection instanceof List) { - list = (List)collection; - } else { - list = new ArrayList(collection); - } - return Collections.unmodifiableList(list); - } - - /** - * Registers a Spring to this BaseSpringSystem so it can be iterated if active. - * @param spring the Spring to register - */ - void registerSpring(Spring spring) { - if (spring == null) { - throw new IllegalArgumentException("spring is required"); - } - if (mSpringRegistry.containsKey(spring.getId())) { - throw new IllegalArgumentException("spring is already registered"); } - mSpringRegistry.put(spring.getId(), spring); - } - - /** - * Deregisters a Spring from this BaseSpringSystem, so it won't be iterated anymore. The Spring should - * not be used anymore after doing this. - * - * @param spring the Spring to deregister - */ - void deregisterSpring(Spring spring) { - if (spring == null) { - throw new IllegalArgumentException("spring is required"); - } - mActiveSprings.remove(spring); - mSpringRegistry.remove(spring.getId()); - } - - /** - * update the springs in the system - * @param deltaTime delta since last update in millis - */ - void advance(double deltaTime) { - for (Spring spring : mActiveSprings) { - // advance time in seconds - if (spring.systemShouldAdvance()) { - spring.advance(deltaTime / 1000.0); - } else { - mActiveSprings.remove(spring); - } - } - } - - /** - * loop the system until idle - */ - public void loop(double ellapsedMillis) { - for (SpringSystemListener listener : mListeners) { - listener.onBeforeIntegrate(this); - } - advance(ellapsedMillis); - if (mActiveSprings.isEmpty()) { - mIdle = true; - } - for (SpringSystemListener listener : mListeners) { - listener.onAfterIntegrate(this); - } - if (mIdle) { - mSpringLooper.stop(); - } - } - - /** - * This is used internally by the {@link Spring}s created by this {@link BaseSpringSystem} to notify - * it has reached a state where it needs to be iterated. This will add the spring to the list of - * active springs on this system and start the iteration if the system was idle before this call. - * @param springId the id of the Spring to be activated - */ - void activateSpring(String springId) { - Spring spring = mSpringRegistry.get(springId); - if (spring == null) { - throw new IllegalArgumentException("springId " + springId + " does not reference a registered spring"); - } - mActiveSprings.add(spring); - if (getIsIdle()) { - mIdle = false; - mSpringLooper.start(); - } - } - - /** listeners **/ - - public void addListener(SpringSystemListener newListener) { - if (newListener == null) { - throw new IllegalArgumentException("newListener is required"); - } - mListeners.add(newListener); - } - - public void removeListener(SpringSystemListener listenerToRemove) { - if (listenerToRemove == null) { - throw new IllegalArgumentException("listenerToRemove is required"); - } - mListeners.remove(listenerToRemove); - } - - public void removeAllListeners() { - mListeners.clear(); - } -} - - diff --git a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/OrigamiValueConverter.java b/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/OrigamiValueConverter.java deleted file mode 100644 index 39f10c16bba9458718d12ae708c9a22a7b468af2..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/OrigamiValueConverter.java +++ /dev/null @@ -1,25 +0,0 @@ -package net.oschina.app.widget.tooglebutton.rebound; - -/** - * Helper math util to convert tension & friction values from the Origami design tool to values that - * the spring system needs. - */ -public class OrigamiValueConverter { - - public static double tensionFromOrigamiValue(double oValue) { - return oValue == 0 ? 0 : (oValue - 30.0) * 3.62 + 194.0; - } - - public static double origamiValueFromTension(double tension) { - return tension == 0 ? 0 : (tension - 194.0) / 3.62 + 30.0; - } - - public static double frictionFromOrigamiValue(double oValue) { - return oValue == 0 ? 0 : (oValue - 8.0) * 3.0 + 25.0; - } - - public static double origamiValueFromFriction(double friction) { - return friction == 0 ? 0 : (friction - 25.0) / 3.0 + 8.0; - } - -} diff --git a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/SimpleSpringListener.java b/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/SimpleSpringListener.java deleted file mode 100644 index 4bc42ae28d7c4887cc47e08c61f5101f94b344bc..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/SimpleSpringListener.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2013, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -package net.oschina.app.widget.tooglebutton.rebound; - -public class SimpleSpringListener implements SpringListener { - @Override - public void onSpringUpdate(Spring spring) { - } - - @Override - public void onSpringAtRest(Spring spring) { - } - - @Override - public void onSpringActivate(Spring spring) { - } - - @Override - public void onSpringEndStateChange(Spring spring) { - } -} diff --git a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/Spring.java b/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/Spring.java deleted file mode 100644 index 494485956e5f68ff4b430625b2584494c940eef3..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/Spring.java +++ /dev/null @@ -1,519 +0,0 @@ -/* - * Copyright (c) 2013, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -package net.oschina.app.widget.tooglebutton.rebound; - -import java.util.concurrent.CopyOnWriteArraySet; - -/** - * Classical spring implementing Hooke's law with configurable friction and tension. - */ -public class Spring { - - // unique incrementer id for springs - private static int ID = 0; - - // maximum amount of time to simulate per physics iteration in seconds (4 frames at 60 FPS) - private static final double MAX_DELTA_TIME_SEC = 0.064; - // fixed timestep to use in the physics solver in seconds - private static final double SOLVER_TIMESTEP_SEC = 0.001; - private SpringConfig mSpringConfig; - private boolean mOvershootClampingEnabled; - - // storage for the current and prior physics state while integration is occurring - private static class PhysicsState { - double position; - double velocity; - } - - // unique id for the spring in the system - private final String mId; - // all physics simulation objects are final and reused in each processing pass - private final PhysicsState mCurrentState = new PhysicsState(); - private final PhysicsState mPreviousState = new PhysicsState(); - private final PhysicsState mTempState = new PhysicsState(); - private double mStartValue; - private double mEndValue; - private boolean mWasAtRest = true; - // thresholds for determining when the spring is at rest - private double mRestSpeedThreshold = 0.005; - private double mDisplacementFromRestThreshold = 0.005; - private CopyOnWriteArraySet mListeners = new CopyOnWriteArraySet(); - private double mTimeAccumulator = 0; - - private final BaseSpringSystem mSpringSystem; - - /** - * create a new spring - */ - Spring(BaseSpringSystem springSystem) { - if (springSystem == null) { - throw new IllegalArgumentException("Spring cannot be created outside of a BaseSpringSystem"); - } - mSpringSystem = springSystem; - mId = "spring:" + ID++; - setSpringConfig(SpringConfig.defaultConfig); - } - - /** - * Destroys this Spring, meaning that it will be deregistered from its BaseSpringSystem so it won't be - * iterated anymore and will clear its set of listeners. Do not use the Spring after calling this, - * doing so may just cause an exception to be thrown. - */ - public void destroy() { - mListeners.clear(); - mSpringSystem.deregisterSpring(this); - } - - /** - * get the unique id for this spring - * @return the unique id - */ - public String getId() { - return mId; - } - - /** - * set the config class - * @param springConfig config class for the spring - * @return this Spring instance for chaining - */ - public Spring setSpringConfig(SpringConfig springConfig) { - if (springConfig == null) { - throw new IllegalArgumentException("springConfig is required"); - } - mSpringConfig = springConfig; - return this; - } - - /** - * retrieve the spring config for this spring - * @return the SpringConfig applied to this spring - */ - public SpringConfig getSpringConfig() { - return mSpringConfig; - } - - /** - * Set the displaced value to determine the displacement for the spring from the rest value. - * This value is retained and used to calculate the displacement ratio. - * This also updates the start value of the Spring. - * @param currentValue the new start and current value for the spring - * @return the spring for chaining - */ - public Spring setCurrentValue(double currentValue) { - mStartValue = currentValue; - mCurrentState.position = currentValue; - mSpringSystem.activateSpring(this.getId()); - for (SpringListener listener : mListeners) { - listener.onSpringUpdate(this); - } - return this; - } - - /** - * Get the displacement value from the last time setCurrentValue was called. - * @return displacement value - */ - public double getStartValue() { - return mStartValue; - } - - /** - * Get the current - * @return current value - */ - public double getCurrentValue() { - return mCurrentState.position; - } - - /** - * get the displacement of the springs current value from its rest value. - * @return the distance displaced by - */ - public double getCurrentDisplacementDistance() { - return getDisplacementDistanceForState(mCurrentState); - } - - /** - * get the displacement from rest for a given physics state - * @param state the state to measure from - * @return the distance displaced by - */ - private double getDisplacementDistanceForState(PhysicsState state) { - return Math.abs(mEndValue - state.position); - } - - /** - * set the rest value to determine the displacement for the spring - * @param endValue the endValue for the spring - * @return the spring for chaining - */ - public Spring setEndValue(double endValue) { - if (mEndValue == endValue && isAtRest()) { - return this; - } - mStartValue = getCurrentValue(); - mEndValue = endValue; - mSpringSystem.activateSpring(this.getId()); - for (SpringListener listener : mListeners) { - listener.onSpringEndStateChange(this); - } - return this; - } - - /** - * get the rest value used for determining the displacement of the spring - * @return the rest value for the spring - */ - public double getEndValue() { - return mEndValue; - } - - /** - * set the velocity on the spring in pixels per second - * @return the spring for chaining - */ - public Spring setVelocity(double velocity) { - mCurrentState.velocity = velocity; - mSpringSystem.activateSpring(this.getId()); - return this; - } - - /** - * get the velocity of the spring - * @return the current velocity - */ - public double getVelocity() { - return mCurrentState.velocity; - } - - /** - * Sets the speed at which the spring should be considered at rest. - * @param restSpeedThreshold speed pixels per second - * @return the spring for chaining - */ - public Spring setRestSpeedThreshold(double restSpeedThreshold) { - mRestSpeedThreshold = restSpeedThreshold; - return this; - } - - /** - * Returns the speed at which the spring should be considered at rest in pixels per second - * @return speed in pixels per second - */ - public double getRestSpeedThreshold() { - return mRestSpeedThreshold; - } - - /** - * set the threshold of displacement from rest below which the spring should be considered at rest - * @param displacementFromRestThreshold displacement to consider resting below - * @return the spring for chaining - */ - public Spring setRestDisplacementThreshold(double displacementFromRestThreshold) { - mDisplacementFromRestThreshold = displacementFromRestThreshold; - return this; - } - - /** - * get the threshold of displacement from rest below which the spring should be considered at rest - * @return displacement to consider resting below - */ - public double getRestDisplacementThreshold() { - return mDisplacementFromRestThreshold; - } - - /** - * Force the spring to clamp at its end value to avoid overshooting the target value. - * @param overshootClampingEnabled whether or not to enable overshoot clamping - * @return the spring for chaining - */ - public Spring setOvershootClampingEnabled(boolean overshootClampingEnabled) { - mOvershootClampingEnabled = overshootClampingEnabled; - return this; - } - - /** - * Check if overshoot clamping is enabled. - * @return is overshoot clamping enabled - */ - public boolean isOvershootClampingEnabled() { - return mOvershootClampingEnabled; - } - - /** - * Check if the spring is overshooting beyond its target. - * @return true if the spring is overshooting its target - */ - public boolean isOvershooting() { - return (mStartValue < mEndValue && getCurrentValue() > mEndValue) || - (mStartValue > mEndValue && getCurrentValue() < mEndValue); - } - - /** - * advance the physics simulation in SOLVER_TIMESTEP_SEC sized chunks to fulfill the required - * realTimeDelta. - * The math is inlined inside the loop since it made a huge performance impact when there are - * several springs being advanced. - * @param time clock time - * @param realDeltaTime clock drift - */ - void advance(double realDeltaTime) { - - boolean isAtRest = isAtRest(); - - if (isAtRest && mWasAtRest) { - /* begin debug - Log.d(TAG, "bailing out because we are at rest:" + getName()); - end debug */ - return; - } - - // clamp the amount of realTime to simulate to avoid stuttering in the UI. We should be able - // to catch up in a subsequent advance if necessary. - double adjustedDeltaTime = realDeltaTime; - if (realDeltaTime > MAX_DELTA_TIME_SEC) { - adjustedDeltaTime = MAX_DELTA_TIME_SEC; - } - - /* begin debug - long startTime = System.currentTimeMillis(); - int iterations = 0; - end debug */ - - mTimeAccumulator += adjustedDeltaTime; - - double tension = mSpringConfig.tension; - double friction = mSpringConfig.friction; - - double position = mCurrentState.position; - double velocity = mCurrentState.velocity; - double tempPosition = mTempState.position; - double tempVelocity = mTempState.velocity; - - double aVelocity, aAcceleration; - double bVelocity, bAcceleration; - double cVelocity, cAcceleration; - double dVelocity, dAcceleration; - - double dxdt, dvdt; - - // iterate over the true time - while (mTimeAccumulator >= SOLVER_TIMESTEP_SEC) { - /* begin debug - iterations++; - end debug */ - mTimeAccumulator -= SOLVER_TIMESTEP_SEC; - - if (mTimeAccumulator < SOLVER_TIMESTEP_SEC) { - // This will be the last iteration. Remember the previous state in case we need to - // interpolate - mPreviousState.position = position; - mPreviousState.velocity = velocity; - } - - // Perform an RK4 integration to provide better detection of the acceleration curve via - // sampling of Euler integrations at 4 intervals feeding each derivative into the calculation - // of the next and taking a weighted sum of the 4 derivatives as the final output. - - // This math was inlined since it made for big performance improvements when advancing several - // springs in one pass of the BaseSpringSystem. - - // The initial derivative is based on the current velocity and the calculated acceleration - aVelocity = velocity; - aAcceleration = (tension * (mEndValue - tempPosition)) - friction * velocity; - - // Calculate the next derivatives starting with the last derivative and integrating over the - // timestep - tempPosition = position + aVelocity * SOLVER_TIMESTEP_SEC * 0.5; - tempVelocity = velocity + aAcceleration * SOLVER_TIMESTEP_SEC * 0.5; - bVelocity = tempVelocity; - bAcceleration = (tension * (mEndValue - tempPosition)) - friction * tempVelocity; - - tempPosition = position + bVelocity * SOLVER_TIMESTEP_SEC * 0.5; - tempVelocity = velocity + bAcceleration * SOLVER_TIMESTEP_SEC * 0.5; - cVelocity = tempVelocity; - cAcceleration = (tension * (mEndValue - tempPosition)) - friction * tempVelocity; - - tempPosition = position + cVelocity * SOLVER_TIMESTEP_SEC; - tempVelocity = velocity + cAcceleration * SOLVER_TIMESTEP_SEC; - dVelocity = tempVelocity; - dAcceleration = (tension * (mEndValue - tempPosition)) - friction * tempVelocity; - - // Take the weighted sum of the 4 derivatives as the final output. - dxdt = 1.0/6.0 * (aVelocity + 2.0 * (bVelocity + cVelocity) + dVelocity); - dvdt = 1.0/6.0 * (aAcceleration + 2.0 * (bAcceleration + cAcceleration) + dAcceleration); - - position += dxdt * SOLVER_TIMESTEP_SEC; - velocity += dvdt * SOLVER_TIMESTEP_SEC; - } - - mTempState.position = tempPosition; - mTempState.velocity = tempVelocity; - - mCurrentState.position = position; - mCurrentState.velocity = velocity; - - if (mTimeAccumulator > 0) { - interpolate(mTimeAccumulator / SOLVER_TIMESTEP_SEC); - } - - // End the spring immediately if it is overshooting and overshoot clamping is enabled. - // Also make sure that if the spring was considered within a resting threshold that it's now - // snapped to its end value. - if (isAtRest() || (mOvershootClampingEnabled && isOvershooting())) { - // Don't call setCurrentValue because that forces a call to onSpringUpdate - mStartValue = mEndValue; - mCurrentState.position = mEndValue; - setVelocity(0); - isAtRest = true; - } - - /* begin debug - long endTime = System.currentTimeMillis(); - long elapsedMillis = endTime - startTime; - Log.d(TAG, - "iterations:" + iterations + - " iterationTime:" + elapsedMillis + - " position:" + mCurrentState.position + - " velocity:" + mCurrentState.velocity + - " realDeltaTime:" + realDeltaTime + - " adjustedDeltaTime:" + adjustedDeltaTime + - " isAtRest:" + isAtRest + - " wasAtRest:" + mWasAtRest); - end debug */ - - // NB: do these checks outside the loop so all listeners are properly notified of the state - // transition - boolean notifyActivate = false; - if (mWasAtRest) { - mWasAtRest = false; - notifyActivate = true; - } - boolean notifyAtRest = false; - if (isAtRest) { - mWasAtRest = true; - notifyAtRest = true; - } - for (SpringListener listener : mListeners) { - // starting to move - if (notifyActivate) { - listener.onSpringActivate(this); - } - - // updated - listener.onSpringUpdate(this); - - // coming to rest - if (notifyAtRest) { - listener.onSpringAtRest(this); - } - } - } - - /** - * Check if this spring should be advanced by the system. * The rule is if the spring is - * currently at rest and it was at rest in the previous advance, the system can skip this spring - * @return should the system process this spring - */ - public boolean systemShouldAdvance() { - return !isAtRest() || !wasAtRest(); - } - - /** - * Check if the spring was at rest in the prior iteration. This is used for ensuring the ending - * callbacks are fired as the spring comes to a rest. - * @return true if the spring was at rest in the prior iteration - */ - public boolean wasAtRest() { - return mWasAtRest; - } - - /** - * check if the current state is at rest - * @return is the spring at rest - */ - public boolean isAtRest() { - return Math.abs(mCurrentState.velocity) <= mRestSpeedThreshold && - getDisplacementDistanceForState(mCurrentState) <= mDisplacementFromRestThreshold; - } - - /** - * Set the spring to be at rest by making its end value equal to its current value and setting - * velocity to 0. - */ - public Spring setAtRest() { - mEndValue = mCurrentState.position; - mTempState.position = mCurrentState.position; - mCurrentState.velocity = 0; - return this; - } - - /** - * linear interpolation between the previous and current physics state based on the amount of - * timestep remaining after processing the rendering delta time in timestep sized chunks. - * @param alpha from 0 to 1, where 0 is the previous state, 1 is the current state - */ - private void interpolate(double alpha) { - mCurrentState.position = mCurrentState.position * alpha + mPreviousState.position *(1-alpha); - mCurrentState.velocity = mCurrentState.velocity * alpha + mPreviousState.velocity *(1-alpha); - } - - /** listeners **/ - - /** - * add a listener - * @param newListener to add - * @return the spring for chaining - */ - public Spring addListener(SpringListener newListener) { - if (newListener == null) { - throw new IllegalArgumentException("newListener is required"); - } - mListeners.add(newListener); - return this; - } - - /** - * remove a listener - * @param listenerToRemove to remove - * @return the spring for chaining - */ - public Spring removeListener(SpringListener listenerToRemove) { - if (listenerToRemove == null) { - throw new IllegalArgumentException("listenerToRemove is required"); - } - mListeners.remove(listenerToRemove); - return this; - } - - /** - * remove all of the listeners - * @return the spring for chaining - */ - public Spring removeAllListeners() { - mListeners.clear(); - return this; - } - - /** - * This method checks to see that the current spring displacement value is equal to the input, - * accounting for the spring's rest displacement threshold. - * @param value The value to compare the spring value to - * @return Whether the displacement value from the spring is within the bounds of the compare - * value, accounting for threshold - */ - public boolean currentValueIsApproximately(double value) { - return Math.abs(getCurrentValue() - value) <= getRestDisplacementThreshold(); - } - -} - diff --git a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/SpringConfig.java b/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/SpringConfig.java deleted file mode 100644 index b95d82a148e627245c8080d8fbce65257030f8a0..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/SpringConfig.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2013, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -package net.oschina.app.widget.tooglebutton.rebound; - -/** - * Data structure for storing spring configuration. - */ -public class SpringConfig { - public double friction; - public double tension; - - public static SpringConfig defaultConfig = SpringConfig.fromOrigamiTensionAndFriction(40, 7); - - /** - * constructor for the SpringConfig - * @param tension tension value for the SpringConfig - * @param friction friction value for the SpringConfig - */ - public SpringConfig(double tension, double friction) { - this.tension = tension; - this.friction = friction; - } - - /** - * A helper to make creating a SpringConfig easier with values mapping to the Origami values. - * @param qcTension tension as defined in the Quartz Composition - * @param qcFriction friction as defined in the Quartz Composition - * @return a SpringConfig that maps to these values - */ - public static SpringConfig fromOrigamiTensionAndFriction(double qcTension, double qcFriction) { - return new SpringConfig( - OrigamiValueConverter.tensionFromOrigamiValue(qcTension), - OrigamiValueConverter.frictionFromOrigamiValue(qcFriction) - ); - } -} diff --git a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/SpringConfigRegistry.java b/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/SpringConfigRegistry.java deleted file mode 100644 index 32b29fc3f1879020c88aebc18670825be693cec1..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/SpringConfigRegistry.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2013, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -package net.oschina.app.widget.tooglebutton.rebound; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -/** - * class for maintaining a registry of all spring configs - */ -public class SpringConfigRegistry { - - private static final SpringConfigRegistry INSTANCE = new SpringConfigRegistry(true); - - public static SpringConfigRegistry getInstance() { - return INSTANCE; - } - - private final Map mSpringConfigMap; - - /** - * constructor for the SpringConfigRegistry - */ - SpringConfigRegistry(boolean includeDefaultEntry) { - mSpringConfigMap = new HashMap(); - if (includeDefaultEntry) { - addSpringConfig(SpringConfig.defaultConfig, "default config"); - } - } - - /** - * add a SpringConfig to the registry - * - * @param springConfig SpringConfig to add to the registry - * @param configName name to give the SpringConfig in the registry - * @return true if the SpringConfig was added, false if a config with that name is already - * present. - */ - public boolean addSpringConfig(SpringConfig springConfig, String configName) { - if (springConfig == null) { - throw new IllegalArgumentException("springConfig is required"); - } - if (configName == null) { - throw new IllegalArgumentException("configName is required"); - } - if (mSpringConfigMap.containsKey(springConfig)) { - return false; - } - mSpringConfigMap.put(springConfig, configName); - return true; - } - - /** - * remove a specific SpringConfig from the registry - * @param springConfig the of the SpringConfig to remove - * @return true if the SpringConfig was removed, false if it was not present. - */ - public boolean removeSpringConfig(SpringConfig springConfig) { - if (springConfig == null) { - throw new IllegalArgumentException("springConfig is required"); - } - return mSpringConfigMap.remove(springConfig) != null; - } - - /** - * retrieve all SpringConfig in the registry - * @return a list of all SpringConfig - */ - public Map getAllSpringConfig() { - return Collections.unmodifiableMap(mSpringConfigMap); - } - - /** - * clear all SpringConfig in the registry - */ - public void removeAllSpringConfig() { - mSpringConfigMap.clear(); - } -} - diff --git a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/SpringListener.java b/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/SpringListener.java deleted file mode 100644 index 705ac67262ce7900ffc6234d063db985abb00458..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/SpringListener.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2013, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -package net.oschina.app.widget.tooglebutton.rebound; - -public interface SpringListener { - - /** - * called whenever the spring is updated - * @param spring the Spring sending the update - */ - void onSpringUpdate(Spring spring); - - /** - * called whenever the spring achieves a resting state - * @param spring the spring that's now resting - */ - void onSpringAtRest(Spring spring); - - /** - * called whenever the spring leaves its resting state - * @param spring the spring that has left its resting state - */ - void onSpringActivate(Spring spring); - - /** - * called whenever the spring notifies of displacement state changes - * @param spring the spring whose end state has changed - */ - void onSpringEndStateChange(Spring spring); -} - diff --git a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/SpringLooper.java b/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/SpringLooper.java deleted file mode 100644 index b05df599a17787b5d672281a22dd5de74acb97eb..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/SpringLooper.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2013, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -package net.oschina.app.widget.tooglebutton.rebound; - -/** - * The spring looper is an interface for implementing platform-dependent run loops. - */ -public abstract class SpringLooper { - - protected BaseSpringSystem mSpringSystem; - - /** - * Set the BaseSpringSystem that the SpringLooper will call back to. - * @param springSystem the spring system to call loop on. - */ - public void setSpringSystem(BaseSpringSystem springSystem) { - mSpringSystem = springSystem; - } - - /** - * The BaseSpringSystem has requested that the looper begins running this {@link Runnable} - * on every frame. The {@link Runnable} will continue running on every frame until - * {@link #stop()} is called. - * If an existing {@link Runnable} had been started on this looper, it will be cancelled. - */ - public abstract void start(); - - /** - * The looper will no longer run the {@link Runnable}. - */ - public abstract void stop(); -} \ No newline at end of file diff --git a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/SpringSystem.java b/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/SpringSystem.java deleted file mode 100644 index a131403362f4d8711167dab4a56eea7fbbe22198..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/SpringSystem.java +++ /dev/null @@ -1,22 +0,0 @@ -package net.oschina.app.widget.tooglebutton.rebound; - -/** - * This is a wrapper for BaseSpringSystem that provides the convenience of automatically providing - * the AndroidSpringLooper dependency in {@link SpringSystem#create}. - */ -public class SpringSystem extends BaseSpringSystem { - - /** - * Create a new SpringSystem providing the appropriate constructor parameters to work properly - * in an Android environment. - * @return the SpringSystem - */ - public static SpringSystem create() { - return new SpringSystem(AndroidSpringLooperFactory.createSpringLooper()); - } - - private SpringSystem(SpringLooper springLooper) { - super(springLooper); - } - -} \ No newline at end of file diff --git a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/SpringSystemListener.java b/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/SpringSystemListener.java deleted file mode 100644 index 9d3086779a9a646064418d279cdcc6044872bcdc..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/SpringSystemListener.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2013, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -package net.oschina.app.widget.tooglebutton.rebound; - -/** - * SpringSystemListener provides an interface for listening to events before and after each Physics - * solving loop the BaseSpringSystem runs. - */ -public interface SpringSystemListener { - - /** - * Runs before each pass through the physics integration loop providing an opportunity to do any - * setup or alterations to the Physics state before integrating. - * @param springSystem the BaseSpringSystem listened to - */ - void onBeforeIntegrate(BaseSpringSystem springSystem); - - /** - * Runs after each pass through the physics integration loop providing an opportunity to do any - * setup or alterations to the Physics state after integrating. - * @param springSystem the BaseSpringSystem listened to - */ - void onAfterIntegrate(BaseSpringSystem springSystem); -} - diff --git a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/SpringUtil.java b/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/SpringUtil.java deleted file mode 100644 index 3b08c48ba2dc01877c71a8dada70f2e34c8af513..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/SpringUtil.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2013, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -package net.oschina.app.widget.tooglebutton.rebound; - -public class SpringUtil { - - /** - * Map a value within a given range to another range. - * - * @param value - * the value to map - * @param fromLow - * the low end of the range the value is within - * @param fromHigh - * the high end of the range the value is within - * @param toLow - * the low end of the range to map to - * @param toHigh - * the high end of the range to map to - * @return the mapped value - */ - public static double mapValueFromRangeToRange(double value, double fromLow, - double fromHigh, double toLow, double toHigh) { - double fromRangeSize = fromHigh - fromLow; - double toRangeSize = toHigh - toLow; - double valueScale = (value - fromLow) / fromRangeSize; - return toLow + (valueScale * toRangeSize); - } - - /** - * Clamp a value to be within the provided range. - * - * @param value - * the value to clamp - * @param low - * the low end of the range - * @param high - * the high end of the range - * @return the clamped value - */ - public static double clamp(double value, double low, double high) { - return Math.min(Math.max(value, low), high); - } - - public static int clamp(int value, int low, int high) { - return Math.min(Math.max(value, low), high); - } -} diff --git a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/SteppingLooper.java b/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/SteppingLooper.java deleted file mode 100644 index f752114fc209db3095365790a5ddfafab6451d7b..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/SteppingLooper.java +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright (c) 2013, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -package net.oschina.app.widget.tooglebutton.rebound; - -public class SteppingLooper extends SpringLooper { - - private boolean mStarted; - private long mLastTime; - - @Override - public void start() { - mStarted = true; - mLastTime = 0; - } - - public boolean step(long interval) { - if (mSpringSystem == null || !mStarted) { - return false; - } - long currentTime = mLastTime + interval; - mSpringSystem.loop(currentTime); - mLastTime = currentTime; - return mSpringSystem.getIsIdle(); - } - - @Override - public void stop() { - mStarted = false; - } -} - diff --git a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/SynchronousLooper.java b/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/SynchronousLooper.java deleted file mode 100644 index c6af03698142f033e36d920bd8369458799d921e..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/SynchronousLooper.java +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright (c) 2013, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -package net.oschina.app.widget.tooglebutton.rebound; - -public class SynchronousLooper extends SpringLooper { - - public static double SIXTY_FPS = 16.6667; - private double mTimeStep; - private boolean mRunning; - - public SynchronousLooper() { - mTimeStep = SIXTY_FPS; - } - - public double getTimeStep() { - return mTimeStep; - } - - public void setTimeStep(double timeStep) { - mTimeStep = timeStep; - } - - @Override - public void start() { - mRunning = true; - while (!mSpringSystem.getIsIdle()) { - if (mRunning == false) { - break; - } - mSpringSystem.loop(mTimeStep); - } - } - - @Override - public void stop() { - mRunning = false; - } -} - diff --git a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/ui/SpringConfiguratorView.java b/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/ui/SpringConfiguratorView.java deleted file mode 100644 index 22fb9b9652db29c17c90216f2bc95b9db53de069..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/ui/SpringConfiguratorView.java +++ /dev/null @@ -1,421 +0,0 @@ -/* - * Copyright (c) 2013, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -package net.oschina.app.widget.tooglebutton.rebound.ui; - -import static net.oschina.app.widget.tooglebutton.rebound.ui.Util.createLayoutParams; -import static net.oschina.app.widget.tooglebutton.rebound.ui.Util.createMatchParams; -import static net.oschina.app.widget.tooglebutton.rebound.ui.Util.createMatchWrapParams; -import static net.oschina.app.widget.tooglebutton.rebound.ui.Util.dpToPx; - -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import net.oschina.app.widget.tooglebutton.rebound.OrigamiValueConverter; -import net.oschina.app.widget.tooglebutton.rebound.Spring; -import net.oschina.app.widget.tooglebutton.rebound.SpringConfig; -import net.oschina.app.widget.tooglebutton.rebound.SpringConfigRegistry; -import net.oschina.app.widget.tooglebutton.rebound.SpringListener; -import net.oschina.app.widget.tooglebutton.rebound.SpringSystem; -import android.annotation.TargetApi; -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Color; -import android.os.Build; -import android.util.AttributeSet; -import android.view.Gravity; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AbsListView; -import android.widget.AdapterView; -import android.widget.BaseAdapter; -import android.widget.FrameLayout; -import android.widget.LinearLayout; -import android.widget.SeekBar; -import android.widget.Spinner; -import android.widget.TableLayout; -import android.widget.TextView; - -/** - * The SpringConfiguratorView provides a reusable view for live-editing all registered springs - * within an Application. Each registered Spring can be accessed by its id and its tension and - * friction properties can be edited while the user tests the effected UI live. - */ -public class SpringConfiguratorView extends FrameLayout { - - private static final int MAX_SEEKBAR_VAL = 100000; - private static final float MIN_TENSION = 0; - private static final float MAX_TENSION = 200; - private static final float MIN_FRICTION = 0; - private static final float MAX_FRICTION = 50; - private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.#"); - - private final SpinnerAdapter spinnerAdapter; - private final List mSpringConfigs = new ArrayList(); - private final Spring mRevealerSpring; - private final float mStashPx; - private final float mRevealPx; - private final SpringConfigRegistry springConfigRegistry; - private final int mTextColor = Color.argb(255, 225, 225, 225); - private SeekBar mTensionSeekBar; - private SeekBar mFrictionSeekBar; - private Spinner mSpringSelectorSpinner; - private TextView mFrictionLabel; - private TextView mTensionLabel; - private SpringConfig mSelectedSpringConfig; - - public SpringConfiguratorView(Context context) { - this(context, null); - } - - public SpringConfiguratorView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - public SpringConfiguratorView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - SpringSystem springSystem = SpringSystem.create(); - springConfigRegistry = SpringConfigRegistry.getInstance(); - spinnerAdapter = new SpinnerAdapter(context); - - Resources resources = getResources(); - mRevealPx = dpToPx(40, resources); - mStashPx = dpToPx(280, resources); - - mRevealerSpring = springSystem.createSpring(); - SpringListener revealerSpringListener = new RevealerSpringListener(); - mRevealerSpring - .setCurrentValue(1) - .setEndValue(1) - .addListener(revealerSpringListener); - - addView(generateHierarchy(context)); - - SeekbarListener seekbarListener = new SeekbarListener(); - mTensionSeekBar.setMax(MAX_SEEKBAR_VAL); - mTensionSeekBar.setOnSeekBarChangeListener(seekbarListener); - - mFrictionSeekBar.setMax(MAX_SEEKBAR_VAL); - mFrictionSeekBar.setOnSeekBarChangeListener(seekbarListener); - - mSpringSelectorSpinner.setAdapter(spinnerAdapter); - mSpringSelectorSpinner.setOnItemSelectedListener(new SpringSelectedListener()); - refreshSpringConfigurations(); - - this.setTranslationY(mStashPx); - } - - /** - * Programmatically build up the view hierarchy to avoid the need for resources. - * @return View hierarchy - */ - @TargetApi(Build.VERSION_CODES.HONEYCOMB) private View generateHierarchy(Context context) { - Resources resources = getResources(); - - FrameLayout.LayoutParams params; - int fivePx = dpToPx(5, resources); - int tenPx = dpToPx(10, resources); - int twentyPx = dpToPx(20, resources); - TableLayout.LayoutParams tableLayoutParams = new TableLayout.LayoutParams( - 0, - ViewGroup.LayoutParams.WRAP_CONTENT, - 1f); - tableLayoutParams.setMargins(0, 0, fivePx, 0); - LinearLayout seekWrapper; - - FrameLayout root = new FrameLayout(context); - params = createLayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dpToPx(300, resources)); - root.setLayoutParams(params); - - FrameLayout container = new FrameLayout(context); - params = createMatchParams(); - params.setMargins(0, twentyPx, 0, 0); - container.setLayoutParams(params); - container.setBackgroundColor(Color.argb(100, 0, 0, 0)); - root.addView(container); - - mSpringSelectorSpinner = new Spinner(context, Spinner.MODE_DIALOG); - params = createMatchWrapParams(); - params.gravity = Gravity.TOP; - params.setMargins(tenPx, tenPx, tenPx, 0); - mSpringSelectorSpinner.setLayoutParams(params); - container.addView(mSpringSelectorSpinner); - - LinearLayout linearLayout = new LinearLayout(context); - params = createMatchWrapParams(); - params.setMargins(0, 0, 0, dpToPx(80, resources)); - params.gravity = Gravity.BOTTOM; - linearLayout.setLayoutParams(params); - linearLayout.setOrientation(LinearLayout.VERTICAL); - container.addView(linearLayout); - - seekWrapper = new LinearLayout(context); - params = createMatchWrapParams(); - params.setMargins(tenPx, tenPx, tenPx, twentyPx); - seekWrapper.setPadding(tenPx, tenPx, tenPx, tenPx); - seekWrapper.setLayoutParams(params); - seekWrapper.setOrientation(LinearLayout.HORIZONTAL); - linearLayout.addView(seekWrapper); - - mTensionSeekBar = new SeekBar(context); - mTensionSeekBar.setLayoutParams(tableLayoutParams); - seekWrapper.addView(mTensionSeekBar); - - mTensionLabel = new TextView(getContext()); - mTensionLabel.setTextColor(mTextColor); - params = createLayoutParams( - dpToPx(50, resources), - ViewGroup.LayoutParams.MATCH_PARENT); - mTensionLabel.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT); - mTensionLabel.setLayoutParams(params); - mTensionLabel.setMaxLines(1); - seekWrapper.addView(mTensionLabel); - - seekWrapper = new LinearLayout(context); - params = createMatchWrapParams(); - params.setMargins(tenPx, tenPx, tenPx, twentyPx); - seekWrapper.setPadding(tenPx, tenPx, tenPx, tenPx); - seekWrapper.setLayoutParams(params); - seekWrapper.setOrientation(LinearLayout.HORIZONTAL); - linearLayout.addView(seekWrapper); - - mFrictionSeekBar = new SeekBar(context); - mFrictionSeekBar.setLayoutParams(tableLayoutParams); - seekWrapper.addView(mFrictionSeekBar); - - mFrictionLabel = new TextView(getContext()); - mFrictionLabel.setTextColor(mTextColor); - params = createLayoutParams(dpToPx(50, resources), ViewGroup.LayoutParams.MATCH_PARENT); - mFrictionLabel.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT); - mFrictionLabel.setLayoutParams(params); - mFrictionLabel.setMaxLines(1); - seekWrapper.addView(mFrictionLabel); - - View nub = new View(context); - params = createLayoutParams(dpToPx(60, resources), dpToPx(40, resources)); - params.gravity = Gravity.TOP | Gravity.CENTER; - nub.setLayoutParams(params); - nub.setOnTouchListener(new OnNubTouchListener()); - nub.setBackgroundColor(Color.argb(255, 0, 164, 209)); - root.addView(nub); - - return root; - } - - /** - * remove the configurator from its parent and clean up springs and listeners - */ - public void destroy() { - ViewGroup parent = (ViewGroup) getParent(); - if (parent != null) { - parent.removeView(this); - } - mRevealerSpring.destroy(); - } - - /** - * reload the springs from the registry and update the UI - */ - public void refreshSpringConfigurations() { - Map springConfigMap = springConfigRegistry.getAllSpringConfig(); - - spinnerAdapter.clear(); - mSpringConfigs.clear(); - - for (Map.Entry entry : springConfigMap.entrySet()) { - if (entry.getKey() == SpringConfig.defaultConfig) { - continue; - } - mSpringConfigs.add(entry.getKey()); - spinnerAdapter.add(entry.getValue()); - } - // Add the default config in last. - mSpringConfigs.add(SpringConfig.defaultConfig); - spinnerAdapter.add(springConfigMap.get(SpringConfig.defaultConfig)); - spinnerAdapter.notifyDataSetChanged(); - if (mSpringConfigs.size() > 0) { - mSpringSelectorSpinner.setSelection(0); - } - } - - private class SpringSelectedListener implements AdapterView.OnItemSelectedListener { - - @Override - public void onItemSelected(AdapterView adapterView, View view, int i, long l) { - mSelectedSpringConfig = mSpringConfigs.get(i); - updateSeekBarsForSpringConfig(mSelectedSpringConfig); - } - - @Override - public void onNothingSelected(AdapterView adapterView) { - } - } - - /** - * listen to events on seekbars and update registered springs accordingly - */ - private class SeekbarListener implements SeekBar.OnSeekBarChangeListener { - - @Override - public void onProgressChanged(SeekBar seekBar, int val, boolean b) { - float tensionRange = MAX_TENSION - MIN_TENSION; - float frictionRange = MAX_FRICTION - MIN_FRICTION; - - if (seekBar == mTensionSeekBar) { - float scaledTension = ((val) * tensionRange) / MAX_SEEKBAR_VAL + MIN_TENSION; - mSelectedSpringConfig.tension = - OrigamiValueConverter.tensionFromOrigamiValue(scaledTension); - String roundedTensionLabel = DECIMAL_FORMAT.format(scaledTension); - mTensionLabel.setText("T:" + roundedTensionLabel); - } - - if (seekBar == mFrictionSeekBar) { - float scaledFriction = ((val) * frictionRange) / MAX_SEEKBAR_VAL + MIN_FRICTION; - mSelectedSpringConfig.friction = - OrigamiValueConverter.frictionFromOrigamiValue(scaledFriction); - String roundedFrictionLabel = DECIMAL_FORMAT.format(scaledFriction); - mFrictionLabel.setText("F:" + roundedFrictionLabel); - } - } - - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - } - } - - /** - * update the position of the seekbars based on the spring value; - * @param springConfig current editing spring - */ - private void updateSeekBarsForSpringConfig(SpringConfig springConfig) { - float tension = (float) OrigamiValueConverter.origamiValueFromTension(springConfig.tension); - float tensionRange = MAX_TENSION - MIN_TENSION; - int scaledTension = Math.round(((tension - MIN_TENSION) * MAX_SEEKBAR_VAL) / tensionRange); - - float friction = (float) OrigamiValueConverter.origamiValueFromFriction(springConfig.friction); - float frictionRange = MAX_FRICTION - MIN_FRICTION; - int scaledFriction = Math.round(((friction - MIN_FRICTION) * MAX_SEEKBAR_VAL) / frictionRange); - - mTensionSeekBar.setProgress(scaledTension); - mFrictionSeekBar.setProgress(scaledFriction); - } - - /** - * toggle visibility when the nub is tapped. - */ - private class OnNubTouchListener implements View.OnTouchListener { - @Override - public boolean onTouch(View view, MotionEvent motionEvent) { - if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { - togglePosition(); - } - return true; - } - } - - private void togglePosition() { - double currentValue = mRevealerSpring.getEndValue(); - mRevealerSpring - .setEndValue(currentValue == 1 ? 0 : 1); - } - - private class RevealerSpringListener implements SpringListener { - - @TargetApi(Build.VERSION_CODES.HONEYCOMB) @Override - public void onSpringUpdate(Spring spring) { - float val = (float) spring.getCurrentValue(); - float minTranslate = mRevealPx; - float maxTranslate = mStashPx; - float range = maxTranslate - minTranslate; - float yTranslate = (val * range) + minTranslate; - SpringConfiguratorView.this.setTranslationY(yTranslate); - } - - @Override - public void onSpringAtRest(Spring spring) { - } - - @Override - public void onSpringActivate(Spring spring) { - } - - @Override - public void onSpringEndStateChange(Spring spring) { - } - } - - private class SpinnerAdapter extends BaseAdapter { - - private final Context mContext; - private final List mStrings; - - public SpinnerAdapter(Context context) { - mContext = context; - mStrings = new ArrayList(); - } - - @Override - public int getCount() { - return mStrings.size(); - } - - @Override - public Object getItem(int position) { - return mStrings.get(position); - } - - @Override - public long getItemId(int position) { - return position; - } - - public void add(String string) { - mStrings.add(string); - notifyDataSetChanged(); - } - - /** - * Remove all elements from the list. - */ - public void clear() { - mStrings.clear(); - notifyDataSetChanged(); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - TextView textView; - if (convertView == null) { - textView = new TextView(mContext); - AbsListView.LayoutParams params = new AbsListView.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT); - textView.setLayoutParams(params); - int twelvePx = dpToPx(12, getResources()); - textView.setPadding(twelvePx, twelvePx, twelvePx, twelvePx); - textView.setTextColor(mTextColor); - } else { - textView = (TextView) convertView; - } - textView.setText(mStrings.get(position)); - return textView; - } - } -} - diff --git a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/ui/Util.java b/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/ui/Util.java deleted file mode 100644 index e25da59694e586eca52d6ecf1a929aba49a3b825..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/oschina/app/widget/tooglebutton/rebound/ui/Util.java +++ /dev/null @@ -1,43 +0,0 @@ -package net.oschina.app.widget.tooglebutton.rebound.ui; - -import android.content.res.Resources; -import android.util.TypedValue; -import android.view.ViewGroup; -import android.widget.FrameLayout; - -/** - * Utilities for generating view hierarchies without using resources. - */ -public abstract class Util { - - public static final int dpToPx(float dp, Resources res) { - return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, - res.getDisplayMetrics()); - } - - public static final FrameLayout.LayoutParams createLayoutParams(int width, - int height) { - return new FrameLayout.LayoutParams(width, height); - } - - public static final FrameLayout.LayoutParams createMatchParams() { - return createLayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT); - } - - public static final FrameLayout.LayoutParams createWrapParams() { - return createLayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, - ViewGroup.LayoutParams.WRAP_CONTENT); - } - - public static final FrameLayout.LayoutParams createWrapMatchParams() { - return createLayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, - ViewGroup.LayoutParams.MATCH_PARENT); - } - - public static final FrameLayout.LayoutParams createMatchWrapParams() { - return createLayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT); - } - -} diff --git a/app/src/main/java/net/oschina/app/wxapi/WXEntryActivity.java b/app/src/main/java/net/oschina/app/wxapi/WXEntryActivity.java index 2aa2e966e744ff944908ff076d3e5479baaf3b4e..482fedf231d9ec947b235620a915408775a84947 100644 --- a/app/src/main/java/net/oschina/app/wxapi/WXEntryActivity.java +++ b/app/src/main/java/net/oschina/app/wxapi/WXEntryActivity.java @@ -4,26 +4,41 @@ import android.app.Activity; import android.app.ProgressDialog; import android.content.Intent; import android.os.Bundle; +import android.support.v4.content.LocalBroadcastManager; +import android.text.TextUtils; +import android.widget.Toast; -import com.loopj.android.http.AsyncHttpResponseHandler; +import com.google.gson.reflect.TypeToken; +import com.loopj.android.http.TextHttpResponseHandler; import com.tencent.mm.sdk.modelbase.BaseResp; import com.tencent.mm.sdk.modelmsg.SendAuth; +import net.oschina.app.AppContext; import net.oschina.app.R; import net.oschina.app.api.ApiHttpClient; +import net.oschina.app.api.remote.OSChinaApi; import net.oschina.app.bean.Constants; -import net.oschina.app.bean.OpenIdCatalog; -import net.oschina.app.ui.LoginBindActivityChooseActivity; -import net.oschina.app.util.DialogHelp; -import net.oschina.app.util.TLog; +import net.oschina.app.improve.account.AccountHelper; +import net.oschina.app.improve.account.base.AccountBaseActivity; +import net.oschina.app.improve.app.AppOperator; +import net.oschina.app.improve.bean.User; +import net.oschina.app.improve.bean.base.ResultBean; +import net.oschina.app.improve.utils.DialogHelper; +import net.oschina.app.util.TDevice; + +import java.lang.reflect.Type; import cz.msebera.android.httpclient.Header; + + /** - * 微信回调的activity - * Created by zhangdeyi on 15/7/27. + * created by fei + * desc: */ public class WXEntryActivity extends Activity { + private ProgressDialog mDialog; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -37,7 +52,41 @@ public class WXEntryActivity extends Activity { handleIntent(intent); } + /** + * show WaitDialog + * + * @return progressDialog + */ + protected ProgressDialog showWaitDialog() { + String message = getResources().getString(R.string.progress_submit); + if (mDialog == null) { + mDialog = DialogHelper.getProgressDialog(this, message); + } + mDialog.show(); + + return mDialog; + } + + /** + * hide waitDialog + */ + protected void hideWaitDialog() { + ProgressDialog dialog = mDialog; + if (dialog != null) { + mDialog = null; + try { + dialog.cancel(); + // dialog.dismiss(); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + } + private void handleIntent(Intent intent) { + if (intent == null) { + return; + } SendAuth.Resp resp = new SendAuth.Resp(intent.getExtras()); if (resp.errCode == BaseResp.ErrCode.ERR_OK) { @@ -45,11 +94,13 @@ public class WXEntryActivity extends Activity { String code = resp.code; String state = resp.state; // 如果不是登录 - if (!state.equals("wechat_login")) { + if (!"wechat_login".equals(state)) { finish(); + } else { + //上面的code就是接入指南里要拿到的code + getAccessTokenAndOpenId(code); } - //上面的code就是接入指南里要拿到的code - getAccessTokenAndOpenId(code); + } else { finish(); } @@ -57,36 +108,119 @@ public class WXEntryActivity extends Activity { // 使用code获取微信的access_token和openid private void getAccessTokenAndOpenId(String code) { - final ProgressDialog waitDialog = DialogHelp.getWaitDialog(this, "加载中..."); + // final ProgressDialog waitDialog = DialogHelp.getWaitDialog(this, "加载中..."); String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&grant_type=authorization_code&code=%s"; String tokenUrl = String.format(url, Constants.WEICHAT_APPID, Constants.WEICHAT_SECRET, code); - ApiHttpClient.getDirect(tokenUrl, new AsyncHttpResponseHandler() { + + if (!HasInternet()) return; + + ApiHttpClient.getDirect(tokenUrl, new TextHttpResponseHandler() { + @Override - public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { - TLog.log("Test", new String(responseBody)); - String openid_info = new String(responseBody); - Intent intent = new Intent(OpenIdCatalog.WECHAT); - intent.putExtra(LoginBindActivityChooseActivity.BUNDLE_KEY_OPENIDINFO, openid_info); - sendBroadcast(intent); - finish(); + public void onStart() { + super.onStart(); + showWaitDialog(); } @Override - public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { - + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + requestFailureHint(throwable); } @Override - public void onStart() { - super.onStart(); - waitDialog.show(); + public void onSuccess(int statusCode, Header[] headers, String responseString) { + + if (!HasInternet()) return; + + //新版微信登录 + if (!TextUtils.isEmpty(responseString)) { + + OSChinaApi.openLogin(OSChinaApi.LOGIN_WECHAT, responseString, new TextHttpResponseHandler() { + + @Override + public void onStart() { + super.onStart(); + // showWaitDialog(); + } + + @Override + public void onFinish() { + super.onFinish(); + //hideWaitDialog(); + } + + @Override + public void onCancel() { + super.onCancel(); + //hideWaitDialog(); + } + + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + requestFailureHint(throwable); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + Type type = new TypeToken>() { + }.getType(); + + ResultBean resultBean = AppOperator.createGson().fromJson(responseString, type); + if (resultBean.isSuccess()) { + User user = resultBean.getResult(); + AccountHelper.login(user, headers); + setResult(RESULT_OK); + finish(); + Intent intent = new Intent(); + intent.setAction(AccountBaseActivity.ACTION_ACCOUNT_FINISH_ALL); + LocalBroadcastManager.getInstance(WXEntryActivity.this).sendBroadcast(intent); + } else { + AppContext.showToast(resultBean.getMessage(), Toast.LENGTH_SHORT); + } + } + }); + } } @Override public void onFinish() { super.onFinish(); - waitDialog.dismiss(); + hideWaitDialog(); + } + + @Override + public void onCancel() { + super.onCancel(); + hideWaitDialog(); } }); } + + private boolean HasInternet() { + if (!TDevice.hasInternet()) { + AppContext.showToast(R.string.tip_network_error, Toast.LENGTH_SHORT); + return false; + } + return true; + } + + + /** + * request network error + * + * @param throwable throwable + */ + private void requestFailureHint(Throwable throwable) { + if (throwable != null) { + throwable.printStackTrace(); + } + AppContext.showToast(getResources().getString(R.string.request_error_hint)); + } + + + @Override + public void onBackPressed() { + super.onBackPressed(); + finish(); + } } diff --git a/app/src/main/jniLibs/armeabi/libBaiduMapSDK_v3_2_0_15.so b/app/src/main/jniLibs/armeabi/libBaiduMapSDK_v3_2_0_15.so deleted file mode 100644 index 4f305c66d78bc4f9be4ffbc6f9653f8f766df2fb..0000000000000000000000000000000000000000 Binary files a/app/src/main/jniLibs/armeabi/libBaiduMapSDK_v3_2_0_15.so and /dev/null differ diff --git a/app/src/main/jniLibs/armeabi/liblocSDK3.so b/app/src/main/jniLibs/armeabi/liblocSDK3.so deleted file mode 100644 index 4451144a91386b11fc8d33a12c23b28c0689136f..0000000000000000000000000000000000000000 Binary files a/app/src/main/jniLibs/armeabi/liblocSDK3.so and /dev/null differ diff --git a/app/src/main/res/anim/anim_alpha_to_hide.xml b/app/src/main/res/anim/anim_alpha_to_hide.xml new file mode 100644 index 0000000000000000000000000000000000000000..f890a7f463bb29cf35e64ad20760beb403cfbb4f --- /dev/null +++ b/app/src/main/res/anim/anim_alpha_to_hide.xml @@ -0,0 +1,5 @@ + + \ No newline at end of file diff --git a/app/src/main/res/anim/audio_animations.xml b/app/src/main/res/anim/audio_animations.xml index 5dc2253d56fad0cb292827f0c01be8c64e397f49..07d6721e519ddac53cbdb18209e06fbea5fa460f 100644 --- a/app/src/main/res/anim/audio_animations.xml +++ b/app/src/main/res/anim/audio_animations.xml @@ -2,13 +2,13 @@ \ No newline at end of file diff --git a/app/src/main/res/anim/in_from_bottom.xml b/app/src/main/res/anim/in_from_bottom.xml deleted file mode 100644 index 38dcc0e908f51a455fce1bc1b0053312eeeead7c..0000000000000000000000000000000000000000 --- a/app/src/main/res/anim/in_from_bottom.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/src/main/res/anim/in_from_top.xml b/app/src/main/res/anim/in_from_top.xml deleted file mode 100644 index d65f83563ce3851cdc489a8cb4321a59fb059e2d..0000000000000000000000000000000000000000 --- a/app/src/main/res/anim/in_from_top.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/src/main/res/anim/out_to_top.xml b/app/src/main/res/anim/out_to_top.xml deleted file mode 100644 index 65ab0f7ff3de07a039b39cd29a628441525903ba..0000000000000000000000000000000000000000 --- a/app/src/main/res/anim/out_to_top.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/src/main/res/anim/out_to_bottom.xml b/app/src/main/res/anim/popup_select_image_hide.xml similarity index 55% rename from app/src/main/res/anim/out_to_bottom.xml rename to app/src/main/res/anim/popup_select_image_hide.xml index b802ccd59693cc288503cd791467baf0ba96b3d3..667eec8b4f82ecbd4aa45fe96aa1854d09886584 100644 --- a/app/src/main/res/anim/out_to_bottom.xml +++ b/app/src/main/res/anim/popup_select_image_hide.xml @@ -1,10 +1,12 @@ - + android:interpolator="@android:anim/accelerate_interpolator"> + - + android:toYDelta="4%p" /> \ No newline at end of file diff --git a/social_sdk_library_project/src/main/res/anim/umeng_socialize_fade_in.xml b/app/src/main/res/anim/popup_select_image_show.xml similarity index 63% rename from social_sdk_library_project/src/main/res/anim/umeng_socialize_fade_in.xml rename to app/src/main/res/anim/popup_select_image_show.xml index 075b19f67c6c8024d13cb5055f72b184183ac15e..949065cd9a18c3ac4255ac4b8e171a126839be3c 100644 --- a/social_sdk_library_project/src/main/res/anim/umeng_socialize_fade_in.xml +++ b/app/src/main/res/anim/popup_select_image_show.xml @@ -1,10 +1,12 @@ - + android:interpolator="@android:anim/decelerate_interpolator"> - + \ No newline at end of file diff --git a/app/src/main/res/anim/quick_option_close.xml b/app/src/main/res/anim/quick_option_close.xml deleted file mode 100644 index 5253a8ed363a996c093a4ea2e7ed5275e0be3621..0000000000000000000000000000000000000000 --- a/app/src/main/res/anim/quick_option_close.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/src/main/res/color/drawer_menu_text.xml b/app/src/main/res/color/btn_select_image_done_bg_selector.xml similarity index 42% rename from app/src/main/res/color/drawer_menu_text.xml rename to app/src/main/res/color/btn_select_image_done_bg_selector.xml index 6ab87ba7ea6b0750faf1c00769df437ab7f188dd..b392fdbfe7331a2063a3a99965ff635854df6138 100644 --- a/app/src/main/res/color/drawer_menu_text.xml +++ b/app/src/main/res/color/btn_select_image_done_bg_selector.xml @@ -1,8 +1,5 @@ - - - - - + + \ No newline at end of file diff --git a/app/src/main/res/color/btn_select_image_preview_bg_selector.xml b/app/src/main/res/color/btn_select_image_preview_bg_selector.xml new file mode 100644 index 0000000000000000000000000000000000000000..85b4a2592fd4440a2ea9d9fc231ae96229b1c1bf --- /dev/null +++ b/app/src/main/res/color/btn_select_image_preview_bg_selector.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/color/feed_back_color.xml b/app/src/main/res/color/feed_back_color.xml new file mode 100644 index 0000000000000000000000000000000000000000..c172ef0a433668eaf45756bcfbc5b4f960bd3948 --- /dev/null +++ b/app/src/main/res/color/feed_back_color.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/social_sdk_library_project/src/main/res/drawable/shake_umeng_socialize_close_button_style.xml b/app/src/main/res/color/shake_text_color.xml similarity index 38% rename from social_sdk_library_project/src/main/res/drawable/shake_umeng_socialize_close_button_style.xml rename to app/src/main/res/color/shake_text_color.xml index d8e856119e233f9c9a4b845bc341a225661df25a..430e381212b75fb5117ee4992fd3977a15eaff33 100644 --- a/social_sdk_library_project/src/main/res/drawable/shake_umeng_socialize_close_button_style.xml +++ b/app/src/main/res/color/shake_text_color.xml @@ -1,5 +1,5 @@ - - - + + + \ No newline at end of file diff --git a/social_sdk_library_project/src/main/res/drawable/shake_umeng_socialize_shake_layout_corner.xml b/app/src/main/res/color/signin_text_color.xml similarity index 41% rename from social_sdk_library_project/src/main/res/drawable/shake_umeng_socialize_shake_layout_corner.xml rename to app/src/main/res/color/signin_text_color.xml index 05c4a130c2f466daa49442fb2f752fc9ffcffcdd..a3bf00b81a39804bd9c33dfd752b423d22111795 100644 --- a/social_sdk_library_project/src/main/res/drawable/shake_umeng_socialize_shake_layout_corner.xml +++ b/app/src/main/res/color/signin_text_color.xml @@ -1,10 +1,7 @@ - - - - - + + \ No newline at end of file diff --git a/app/src/main/res/color/text_sign_selector.xml b/app/src/main/res/color/text_sign_selector.xml new file mode 100644 index 0000000000000000000000000000000000000000..74cc06c325d3d1a6e411b6fcf4ffc6a3943b7753 --- /dev/null +++ b/app/src/main/res/color/text_sign_selector.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/color/tweet_publish_send.xml b/app/src/main/res/color/tweet_publish_send.xml new file mode 100644 index 0000000000000000000000000000000000000000..dc784c4ab91e383ca10430fee39315d47ce45ced --- /dev/null +++ b/app/src/main/res/color/tweet_publish_send.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-hdpi/bg_edittext_nor.9.png b/app/src/main/res/drawable-hdpi/bg_edittext_nor.9.png deleted file mode 100644 index 41e6c6cc54e01a2ae0afc31a0bc6361f93d3e20b..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/bg_edittext_nor.9.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/bg_edittext_sel.9.png b/app/src/main/res/drawable-hdpi/bg_edittext_sel.9.png deleted file mode 100644 index 2269f09223f84a8d8fac80fbc4e01e04d6094e5f..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/bg_edittext_sel.9.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/btn_blue_normal.9.png b/app/src/main/res/drawable-hdpi/btn_blue_normal.9.png deleted file mode 100644 index d3f604d136515f1370c395b9f14eed928e6df705..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/btn_blue_normal.9.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/btn_blue_pressed.9.png b/app/src/main/res/drawable-hdpi/btn_blue_pressed.9.png deleted file mode 100644 index 1276c4fe0fbb6784d30e6f1fae2893eec5b2d161..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/btn_blue_pressed.9.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/btn_emoji.png b/app/src/main/res/drawable-hdpi/btn_emoji.png deleted file mode 100644 index 386d474a66e47d7e0b64becb3df7501224fa269b..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/btn_emoji.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/btn_emoji_pressed.png b/app/src/main/res/drawable-hdpi/btn_emoji_pressed.png deleted file mode 100644 index 037ccc49db4a1aa36642c9b906d52f796e7dcf6c..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/btn_emoji_pressed.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/btn_item_opt_more_normal.png b/app/src/main/res/drawable-hdpi/btn_item_opt_more_normal.png deleted file mode 100644 index af537a20afa4fb1e1734cad50acf6dc5e27df8fd..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/btn_item_opt_more_normal.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/btn_small_green_normal.9.png b/app/src/main/res/drawable-hdpi/btn_small_green_normal.9.png deleted file mode 100644 index 3c5f8f95511b434457ea84d37aadec910fe32b11..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/btn_small_green_normal.9.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/btn_small_green_pressed.9.png b/app/src/main/res/drawable-hdpi/btn_small_green_pressed.9.png deleted file mode 100644 index f726db5cb2c582c405a39ced9ca5a2c8e0818019..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/btn_small_green_pressed.9.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/btn_small_white_normal.9.png b/app/src/main/res/drawable-hdpi/btn_small_white_normal.9.png deleted file mode 100644 index 7c83f7a057afa4d03da038aa907d34342c77089b..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/btn_small_white_normal.9.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/btn_small_white_pressed.9.png b/app/src/main/res/drawable-hdpi/btn_small_white_pressed.9.png deleted file mode 100644 index ee8ae9276f4f25484c00d5dc60490ade69cabab9..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/btn_small_white_pressed.9.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/btn_white_normal.9.png b/app/src/main/res/drawable-hdpi/btn_white_normal.9.png deleted file mode 100644 index 3bfd68b60357b9addbfa16d7ec30b2ea547f62d4..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/btn_white_normal.9.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/btn_white_pressed.9.png b/app/src/main/res/drawable-hdpi/btn_white_pressed.9.png deleted file mode 100644 index 60fe7b5eb60c7ae2a26a878ce224f6d0e2ab6e77..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/btn_white_pressed.9.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/comment_refer_container_bg.9.png b/app/src/main/res/drawable-hdpi/comment_refer_container_bg.9.png deleted file mode 100644 index 7e03da1949e4bfe0ac366c24c1106c2cd7ad37a7..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/comment_refer_container_bg.9.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/compose_toolbar_keyboard_normal.png b/app/src/main/res/drawable-hdpi/compose_toolbar_keyboard_normal.png deleted file mode 100644 index f6ee84be9781ec4bdab70c658db62e83ce4e002b..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/compose_toolbar_keyboard_normal.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/day_comment_reply_container_bg.9.png b/app/src/main/res/drawable-hdpi/day_comment_reply_container_bg.9.png deleted file mode 100644 index 38b20d85b241029ec085100b3a584cd6c68a3e59..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/day_comment_reply_container_bg.9.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/drawer_menu_icon_blog_nor.png b/app/src/main/res/drawable-hdpi/drawer_menu_icon_blog_nor.png deleted file mode 100644 index d52438778338484e356f99b6d7f91327fc5c3501..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/drawer_menu_icon_blog_nor.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/drawer_menu_icon_gitapp_nor.png b/app/src/main/res/drawable-hdpi/drawer_menu_icon_gitapp_nor.png deleted file mode 100644 index adce8e177193672ddd0d85c5d4031f8129138ba7..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/drawer_menu_icon_gitapp_nor.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/drawer_menu_icon_night_nor.png b/app/src/main/res/drawable-hdpi/drawer_menu_icon_night_nor.png deleted file mode 100644 index a300e956b30939772458e0fbb7d165da27d36eda..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/drawer_menu_icon_night_nor.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/drawer_menu_icon_opensoft_nor.png b/app/src/main/res/drawable-hdpi/drawer_menu_icon_opensoft_nor.png deleted file mode 100644 index f09b50b90131d16a7e6ea70ab1d4ce2f6aea0242..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/drawer_menu_icon_opensoft_nor.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/drawer_menu_icon_quest_nor.png b/app/src/main/res/drawable-hdpi/drawer_menu_icon_quest_nor.png deleted file mode 100644 index eba2951660610589417ea44618f50d708195c1b2..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/drawer_menu_icon_quest_nor.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/drawer_menu_icon_setting_nor.png b/app/src/main/res/drawable-hdpi/drawer_menu_icon_setting_nor.png deleted file mode 100644 index 309faa61d093826278e5154a9c1860bf51014f51..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/drawer_menu_icon_setting_nor.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/drawer_shadow.9.png b/app/src/main/res/drawable-hdpi/drawer_shadow.9.png deleted file mode 100644 index 236bff558af07faa3921ba35e2515edf62d04bb9..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/drawer_shadow.9.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/ic_add_follow.png b/app/src/main/res/drawable-hdpi/ic_add_follow.png deleted file mode 100644 index 5a185d8ff95aee567d64c154c37afdcd5b93dacd..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/ic_add_follow.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/ic_axis_line.9.png b/app/src/main/res/drawable-hdpi/ic_axis_line.9.png deleted file mode 100644 index 888933443b3fac9cd7525bbb33298904c33ec14b..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/ic_axis_line.9.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/ic_drawer.png b/app/src/main/res/drawable-hdpi/ic_drawer.png deleted file mode 100644 index 6591044ace7491bd2bf2abe9c15b5e56d0e189de..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/ic_drawer.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/ic_follow_each_other.png b/app/src/main/res/drawable-hdpi/ic_follow_each_other.png deleted file mode 100644 index 6a590967e20446f600ad4a24f1e3c4fd09712dc9..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/ic_follow_each_other.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/ic_followed.png b/app/src/main/res/drawable-hdpi/ic_followed.png deleted file mode 100644 index 5b35db7fba267015100c92b4745724a3f0f8311f..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/ic_followed.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/ic_launcher.png b/app/src/main/res/drawable-hdpi/ic_launcher.png deleted file mode 100644 index daa125f5ad3ecd8d617fe5129f80815ae4d05c36..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/ic_launcher.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/ic_private_message.png b/app/src/main/res/drawable-hdpi/ic_private_message.png deleted file mode 100644 index cfcd57bb5298a2ce490de0f5062d3b2060177ceb..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/ic_private_message.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/icon_explore_event.png b/app/src/main/res/drawable-hdpi/icon_explore_event.png deleted file mode 100644 index 8799d5aa4b0e9fa7599dedcec73bc92ee82bb8bd..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/icon_explore_event.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/icon_explore_finduser.png b/app/src/main/res/drawable-hdpi/icon_explore_finduser.png deleted file mode 100644 index 92e86d67626c6c095e1153c4dbcc79430db230e1..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/icon_explore_finduser.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/icon_explore_friends.png b/app/src/main/res/drawable-hdpi/icon_explore_friends.png deleted file mode 100644 index 2a1e8b3e212c4dbf16828e4b000cb710b8d56dbc..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/icon_explore_friends.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/icon_explore_samecity.png b/app/src/main/res/drawable-hdpi/icon_explore_samecity.png deleted file mode 100644 index 5d3f9cbd16049e30ffaa4e6c78c97a1fa8587122..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/icon_explore_samecity.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/icon_explore_scan.png b/app/src/main/res/drawable-hdpi/icon_explore_scan.png deleted file mode 100644 index c7c23cd6753d1a3bf1f18fb100f97345d13c369a..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/icon_explore_scan.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/icon_explore_shake.png b/app/src/main/res/drawable-hdpi/icon_explore_shake.png deleted file mode 100644 index 0a3b1fad4a1eff49337245a76a9789c11ceea951..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/icon_explore_shake.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/icon_gcoding.png b/app/src/main/res/drawable-hdpi/icon_gcoding.png deleted file mode 100644 index 16adf262f3baaa3c56d659fb46445f2a61bc111d..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/icon_gcoding.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/icon_link.png b/app/src/main/res/drawable-hdpi/icon_link.png deleted file mode 100644 index f447453cda888925bfb7bc58547aa3fcd16ce06d..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/icon_link.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/icon_loginout.png b/app/src/main/res/drawable-hdpi/icon_loginout.png deleted file mode 100644 index 94e361718e840da433f40a518cc7ca94f938b3af..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/icon_loginout.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/icon_my_blog.png b/app/src/main/res/drawable-hdpi/icon_my_blog.png deleted file mode 100644 index c402b318b09a0879dd2d4d49c442dea353824bf8..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/icon_my_blog.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/icon_my_message.png b/app/src/main/res/drawable-hdpi/icon_my_message.png deleted file mode 100644 index fd403e7608ec7358e35c0d4d3c45c7df4efe34f0..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/icon_my_message.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/icon_my_note.png b/app/src/main/res/drawable-hdpi/icon_my_note.png deleted file mode 100644 index d4c1d5006318aba6ea2105263cd5ea577aec5f8a..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/icon_my_note.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/icon_my_team.png b/app/src/main/res/drawable-hdpi/icon_my_team.png deleted file mode 100644 index 470c593d673ce418c69fe7495db5c85a6d08ca4a..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/icon_my_team.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/icon_pic_menu.png b/app/src/main/res/drawable-hdpi/icon_pic_menu.png deleted file mode 100644 index 16db8135d94aff93d215d3b6bf8d9a213b88b815..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/icon_pic_menu.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/icon_qr_code.png b/app/src/main/res/drawable-hdpi/icon_qr_code.png deleted file mode 100644 index 4163f157849d063d6b0d53b68e9cc4f71c2d44f0..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/icon_qr_code.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/messages_left_bubble.9.png b/app/src/main/res/drawable-hdpi/messages_left_bubble.9.png deleted file mode 100644 index e11349ec4636cbfbee227d4b37ec145064f8ad47..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/messages_left_bubble.9.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/messages_left_bubble_highlighted.9.png b/app/src/main/res/drawable-hdpi/messages_left_bubble_highlighted.9.png deleted file mode 100644 index 432ee9368299ea5d76fd2bc351aec916064008a6..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/messages_left_bubble_highlighted.9.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/plus1.png b/app/src/main/res/drawable-hdpi/plus1.png deleted file mode 100644 index 81786c1d8f5ed810fd8351f74996f9b64dbf5ffb..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/plus1.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/shaking.png b/app/src/main/res/drawable-hdpi/shaking.png deleted file mode 100644 index b6597071202d6c84fd174eeaf80ef36894eb6f31..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/shaking.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/sliding_tab_strip_background.9.png b/app/src/main/res/drawable-hdpi/sliding_tab_strip_background.9.png deleted file mode 100644 index f2e23251e93911c343ff772f8233e094108eac72..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/sliding_tab_strip_background.9.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/textfield_normal.9.png b/app/src/main/res/drawable-hdpi/textfield_normal.9.png deleted file mode 100644 index c4346b85e89f2d8aca196c9caacf5d2833acc4ee..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/textfield_normal.9.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/textfield_selected.9.png b/app/src/main/res/drawable-hdpi/textfield_selected.9.png deleted file mode 100644 index d383f4bd43db1755025c6bb6d1c2a8906aee176d..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/textfield_selected.9.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/user_center_bg.png b/app/src/main/res/drawable-hdpi/user_center_bg.png deleted file mode 100644 index e557a0ffc8dedd8027f3d88b59b8cf0eb5b5866a..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/user_center_bg.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/welcome.jpeg b/app/src/main/res/drawable-hdpi/welcome.jpeg deleted file mode 100644 index 160f6a184d785a021f8acdd81b2d6737b9734137..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/welcome.jpeg and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/widget_bar_explore_nor.png b/app/src/main/res/drawable-hdpi/widget_bar_explore_nor.png deleted file mode 100644 index 674d39d8d11a1b052fca3cc700e94ba1c1691b08..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/widget_bar_explore_nor.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/widget_bar_explore_over.png b/app/src/main/res/drawable-hdpi/widget_bar_explore_over.png deleted file mode 100644 index bb517eec3ca2f716071e1d0a459131a21d7f87dd..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/widget_bar_explore_over.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/widget_bar_me_nor.png b/app/src/main/res/drawable-hdpi/widget_bar_me_nor.png deleted file mode 100644 index 1a9c310d1a3677c01cf6a74a4f4e3deb4d529e19..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/widget_bar_me_nor.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/widget_bar_me_over.png b/app/src/main/res/drawable-hdpi/widget_bar_me_over.png deleted file mode 100644 index 1456fa80fdf78b300342bb5e3925d8d96132c3fd..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/widget_bar_me_over.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/widget_bar_news_nor.png b/app/src/main/res/drawable-hdpi/widget_bar_news_nor.png deleted file mode 100644 index 170903ce9284ba846c46286e1ae67dcb654493aa..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/widget_bar_news_nor.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/widget_bar_news_over.png b/app/src/main/res/drawable-hdpi/widget_bar_news_over.png deleted file mode 100644 index b08eacb50eb10a73388f6e2d0c3aa1d3c873081e..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/widget_bar_news_over.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/widget_bar_tweet_nor.png b/app/src/main/res/drawable-hdpi/widget_bar_tweet_nor.png deleted file mode 100644 index 24f4b4e92926a94b129b4574ecc1b2baf64956da..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/widget_bar_tweet_nor.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/widget_bar_tweet_over.png b/app/src/main/res/drawable-hdpi/widget_bar_tweet_over.png deleted file mode 100644 index 34b3cf4d19c242550e09f66d8b39ecb7b16e7942..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/widget_bar_tweet_over.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/drawer_shadow.9.png b/app/src/main/res/drawable-mdpi/drawer_shadow.9.png deleted file mode 100644 index ffe3a28d77c72094021013c6442560803b3d344c..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-mdpi/drawer_shadow.9.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/ic_drawer.png b/app/src/main/res/drawable-mdpi/ic_drawer.png deleted file mode 100644 index c6da5a898bc114ed3c4f496e1e22bb70592bda09..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-mdpi/ic_drawer.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/icon_save.jpg b/app/src/main/res/drawable-mdpi/icon_save.jpg deleted file mode 100644 index d8e1538907ccbb5f51ee7245b9e37e1c423c6886..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-mdpi/icon_save.jpg and /dev/null differ diff --git a/app/src/main/res/drawable-v21/ic_material.xml b/app/src/main/res/drawable-v21/ic_material.xml new file mode 100644 index 0000000000000000000000000000000000000000..c98eeff73c89aaa8ce74e3b5a1d76fd2b4058ef3 --- /dev/null +++ b/app/src/main/res/drawable-v21/ic_material.xml @@ -0,0 +1,4 @@ + + \ No newline at end of file diff --git a/app/src/main/res/drawable-xhdpi/btn_clear_input_normal.png b/app/src/main/res/drawable-xhdpi/btn_clear_input_normal.png deleted file mode 100644 index ffef997ba8c208b8ee60405fa18c5889971d5e87..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-xhdpi/btn_clear_input_normal.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/btn_clear_input_pressed.png b/app/src/main/res/drawable-xhdpi/btn_clear_input_pressed.png deleted file mode 100644 index 67c59260b74ebf4d5b9fd2ff3b36d99323de1654..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-xhdpi/btn_clear_input_pressed.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/btn_del_nor.9.png b/app/src/main/res/drawable-xhdpi/btn_del_nor.9.png deleted file mode 100644 index f2d980d6990d125c4dfe4dcf189bfde275986851..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-xhdpi/btn_del_nor.9.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/btn_del_press.9.png b/app/src/main/res/drawable-xhdpi/btn_del_press.9.png deleted file mode 100644 index 6f3d718e3df4e54694964891182563c2e1b7287f..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-xhdpi/btn_del_press.9.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/btn_emoji_normal.png b/app/src/main/res/drawable-xhdpi/btn_emoji_normal.png deleted file mode 100644 index 386d474a66e47d7e0b64becb3df7501224fa269b..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-xhdpi/btn_emoji_normal.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/btn_emoji_pressed.png b/app/src/main/res/drawable-xhdpi/btn_emoji_pressed.png deleted file mode 100644 index 037ccc49db4a1aa36642c9b906d52f796e7dcf6c..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-xhdpi/btn_emoji_pressed.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/btn_quickoption_nor.png b/app/src/main/res/drawable-xhdpi/btn_quickoption_nor.png deleted file mode 100644 index 4dc28e854fedddb335af8b2c40e28cf0db3ea91c..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-xhdpi/btn_quickoption_nor.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/btn_quickoption_pressed.png b/app/src/main/res/drawable-xhdpi/btn_quickoption_pressed.png deleted file mode 100644 index e2faebb40f2b430c9089b46ab395f9c38fe177d4..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-xhdpi/btn_quickoption_pressed.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/btn_quickoption_route.png b/app/src/main/res/drawable-xhdpi/btn_quickoption_route.png deleted file mode 100644 index fe002214c08f7291217e36ddc8111a3071da85ec..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-xhdpi/btn_quickoption_route.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/detail_map_guide.png b/app/src/main/res/drawable-xhdpi/detail_map_guide.png deleted file mode 100644 index a9245e3e91008ee4fdd37dfa2481e5a55e11eae3..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-xhdpi/detail_map_guide.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/drawer_shadow.9.png b/app/src/main/res/drawable-xhdpi/drawer_shadow.9.png deleted file mode 100644 index fabe9d96563785c7d6b008bb3d8da25e816c343c..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-xhdpi/drawer_shadow.9.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/edit_normal.9.png b/app/src/main/res/drawable-xhdpi/edit_normal.9.png deleted file mode 100644 index 6244b87a291be490cf421d7fab03b927c03fc2c9..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-xhdpi/edit_normal.9.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_drawer.png b/app/src/main/res/drawable-xhdpi/ic_drawer.png deleted file mode 100644 index 0d333852357025e7b00591971d7be315724769a1..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_drawer.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_launcher.png b/app/src/main/res/drawable-xhdpi/ic_launcher.png deleted file mode 100644 index c2f65bd7563572a78f5eb0df0f248e2a3544d860..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_launcher.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/icon_download.png b/app/src/main/res/drawable-xhdpi/icon_download.png deleted file mode 100644 index 2a290253240ce7d890809df8e0c49cabcd6c847d..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-xhdpi/icon_download.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/notification_bg.9.png b/app/src/main/res/drawable-xhdpi/notification_bg.9.png deleted file mode 100644 index 13496b4e3181ad40d873235f903bfc728740a538..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-xhdpi/notification_bg.9.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/pagefailed_bg.png b/app/src/main/res/drawable-xhdpi/pagefailed_bg.png deleted file mode 100644 index e09cc518a9b8c5a461f7be3cd351cb650f9c930c..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-xhdpi/pagefailed_bg.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/spinner_ab_default_holo_dark_am.9.png b/app/src/main/res/drawable-xhdpi/spinner_ab_default_holo_dark_am.9.png deleted file mode 100644 index a5694afb07688c129916caa96845954823a69887..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-xhdpi/spinner_ab_default_holo_dark_am.9.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/drawer_shadow.9.png b/app/src/main/res/drawable-xxhdpi/drawer_shadow.9.png deleted file mode 100644 index b91e9d7f285e8110ba3ba4e72cc6f0416eb3a30a..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-xxhdpi/drawer_shadow.9.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_drawer.png b/app/src/main/res/drawable-xxhdpi/ic_drawer.png deleted file mode 100644 index 5fda55323368a73c0940187dfb84d636c7d1b367..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_drawer.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_launcher.png b/app/src/main/res/drawable-xxhdpi/ic_launcher.png deleted file mode 100644 index c07990234db4497794305b47641be8351f197cea..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/icon_actionbar_home.png b/app/src/main/res/drawable-xxhdpi/icon_actionbar_home.png deleted file mode 100644 index b613e65bf58570af28b2f595897919a98759a1bf..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-xxhdpi/icon_actionbar_home.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/bg_balloon_left.9.png b/app/src/main/res/drawable-xxxhdpi/bg_balloon_left.9.png new file mode 100644 index 0000000000000000000000000000000000000000..d09d47c6684c1654bb27f5b2d80bc37bf150b5fd Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/bg_balloon_left.9.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/bg_balloon_right.9.png b/app/src/main/res/drawable-xxxhdpi/bg_balloon_right.9.png new file mode 100644 index 0000000000000000000000000000000000000000..4e45f58864ddc4af5f69e3f870388e495478058f Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/bg_balloon_right.9.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/bg_login_thirdpart.9.png b/app/src/main/res/drawable-xxxhdpi/bg_login_thirdpart.9.png new file mode 100644 index 0000000000000000000000000000000000000000..7f64168e987213e180a582fb0917b19d6e855dd7 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/bg_login_thirdpart.9.png differ diff --git a/app/src/main/res/drawable/btn_green_selector.xml b/app/src/main/res/drawable-xxxhdpi/ic_title_bar_icon_bg.xml similarity index 33% rename from app/src/main/res/drawable/btn_green_selector.xml rename to app/src/main/res/drawable-xxxhdpi/ic_title_bar_icon_bg.xml index 6cdb2596b7aadbbf9f8d5e8fd3f39db66ec37eb4..af0ce6bfa81393517d31ee925b49bb2acb434b47 100644 --- a/app/src/main/res/drawable/btn_green_selector.xml +++ b/app/src/main/res/drawable-xxxhdpi/ic_title_bar_icon_bg.xml @@ -1,7 +1,10 @@ - - - - + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/banner_linear_bg.xml b/app/src/main/res/drawable/banner_linear_bg.xml new file mode 100644 index 0000000000000000000000000000000000000000..054b0df65216a679a64e03bc59ec7d9c4bbdaa99 --- /dev/null +++ b/app/src/main/res/drawable/banner_linear_bg.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_comment.xml b/app/src/main/res/drawable/bg_comment.xml new file mode 100644 index 0000000000000000000000000000000000000000..e3396417e8b53a4fcefb3bb47fd9b3a787240d2c --- /dev/null +++ b/app/src/main/res/drawable/bg_comment.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_edittext.xml b/app/src/main/res/drawable/bg_edittext.xml deleted file mode 100644 index af67fa2c09cfe39071347593060302c80ca89ae1..0000000000000000000000000000000000000000 --- a/app/src/main/res/drawable/bg_edittext.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_event_detail_ing.xml b/app/src/main/res/drawable/bg_event_detail_ing.xml new file mode 100644 index 0000000000000000000000000000000000000000..efd8c0d88bae070f98fbce909845e3b69c8afbed --- /dev/null +++ b/app/src/main/res/drawable/bg_event_detail_ing.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/social_sdk_library_project/src/main/res/drawable/shake_umeng_socialize_imgview_border.xml b/app/src/main/res/drawable/bg_event_end.xml similarity index 57% rename from social_sdk_library_project/src/main/res/drawable/shake_umeng_socialize_imgview_border.xml rename to app/src/main/res/drawable/bg_event_end.xml index 80e1f0da745812c43a5461a5eb359975227df805..95cde8894c52b78146c4c534c0c5ea37662b33d0 100644 --- a/social_sdk_library_project/src/main/res/drawable/shake_umeng_socialize_imgview_border.xml +++ b/app/src/main/res/drawable/bg_event_end.xml @@ -1,8 +1,5 @@ - - - - + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_event_ing.xml b/app/src/main/res/drawable/bg_event_ing.xml new file mode 100644 index 0000000000000000000000000000000000000000..7b7e857d75a74c62395b11a48bc763a8af615a1a --- /dev/null +++ b/app/src/main/res/drawable/bg_event_ing.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_event_signin_submit.xml b/app/src/main/res/drawable/bg_event_signin_submit.xml new file mode 100644 index 0000000000000000000000000000000000000000..d5f739d9f3ecd5f45a1518f6c75ef6bec2cf08ed --- /dev/null +++ b/app/src/main/res/drawable/bg_event_signin_submit.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/social_sdk_library_project/src/main/res/drawable/btn_red_normal.xml b/app/src/main/res/drawable/bg_event_type.xml similarity index 51% rename from social_sdk_library_project/src/main/res/drawable/btn_red_normal.xml rename to app/src/main/res/drawable/bg_event_type.xml index 5300a4bce5c72ea6fe5887f7c7387714b1a6b508..95cde8894c52b78146c4c534c0c5ea37662b33d0 100644 --- a/social_sdk_library_project/src/main/res/drawable/btn_red_normal.xml +++ b/app/src/main/res/drawable/bg_event_type.xml @@ -1,5 +1,5 @@ - - - + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_login_input_error.xml b/app/src/main/res/drawable/bg_login_input_error.xml new file mode 100644 index 0000000000000000000000000000000000000000..f36c4bc32248f4cd527fcdaaa8874cb7da548d5b --- /dev/null +++ b/app/src/main/res/drawable/bg_login_input_error.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_login_input_ok.xml b/app/src/main/res/drawable/bg_login_input_ok.xml new file mode 100644 index 0000000000000000000000000000000000000000..893273aea77d409b213c1a4e4ff514afe8af9871 --- /dev/null +++ b/app/src/main/res/drawable/bg_login_input_ok.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_login_navigation_bar.xml b/app/src/main/res/drawable/bg_login_navigation_bar.xml new file mode 100644 index 0000000000000000000000000000000000000000..9f03bd2de8b25cabd6a8fea372b67e7f7def7912 --- /dev/null +++ b/app/src/main/res/drawable/bg_login_navigation_bar.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_login_register.xml b/app/src/main/res/drawable/bg_login_register.xml new file mode 100644 index 0000000000000000000000000000000000000000..d974602fd8472c3fdae3a2d379cc998a7546d7b4 --- /dev/null +++ b/app/src/main/res/drawable/bg_login_register.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_login_submit.xml b/app/src/main/res/drawable/bg_login_submit.xml new file mode 100644 index 0000000000000000000000000000000000000000..a3d07fa9cee2bc9a59cecb9996eedc157e1b62d5 --- /dev/null +++ b/app/src/main/res/drawable/bg_login_submit.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_login_submit_lock.xml b/app/src/main/res/drawable/bg_login_submit_lock.xml new file mode 100644 index 0000000000000000000000000000000000000000..a62f9f9c1f186fef5337b1ad1e102cd86b608781 --- /dev/null +++ b/app/src/main/res/drawable/bg_login_submit_lock.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/social_sdk_library_project/src/main/res/drawable/btn_red_unable.xml b/app/src/main/res/drawable/bg_normal.xml similarity index 50% rename from social_sdk_library_project/src/main/res/drawable/btn_red_unable.xml rename to app/src/main/res/drawable/bg_normal.xml index e6941215c35cf877ea5ca54389048e55165394cb..23971ae8eae2aa704c4ab22854a25afc92245e9f 100644 --- a/social_sdk_library_project/src/main/res/drawable/btn_red_unable.xml +++ b/app/src/main/res/drawable/bg_normal.xml @@ -1,6 +1,4 @@ - - - + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_notebook.xml b/app/src/main/res/drawable/bg_notebook.xml deleted file mode 100644 index 693b6e8a79e58c2aa242abe678ac40dbccb98302..0000000000000000000000000000000000000000 --- a/app/src/main/res/drawable/bg_notebook.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_register_call_sms.xml b/app/src/main/res/drawable/bg_register_call_sms.xml new file mode 100644 index 0000000000000000000000000000000000000000..f5532fbc88cb4b259d08a0896a88627b8697ff3d --- /dev/null +++ b/app/src/main/res/drawable/bg_register_call_sms.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_sign_up.xml b/app/src/main/res/drawable/bg_sign_up.xml new file mode 100644 index 0000000000000000000000000000000000000000..1fa0e323ce4a4754111f430339ee06ab9311b51c --- /dev/null +++ b/app/src/main/res/drawable/bg_sign_up.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_signin_input_error.xml b/app/src/main/res/drawable/bg_signin_input_error.xml new file mode 100644 index 0000000000000000000000000000000000000000..78448600bfd1fd3256de4dc007fea92dc0b8bae4 --- /dev/null +++ b/app/src/main/res/drawable/bg_signin_input_error.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_signin_input_ok.xml b/app/src/main/res/drawable/bg_signin_input_ok.xml new file mode 100644 index 0000000000000000000000000000000000000000..66157aa147b1f423f022b10d835c9fcf46efc6e7 --- /dev/null +++ b/app/src/main/res/drawable/bg_signin_input_ok.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_text_comment.xml b/app/src/main/res/drawable/bg_text_comment.xml new file mode 100644 index 0000000000000000000000000000000000000000..b74daea3939b733332079fe9612693e2a22b693e --- /dev/null +++ b/app/src/main/res/drawable/bg_text_comment.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_type.xml b/app/src/main/res/drawable/bg_type.xml new file mode 100644 index 0000000000000000000000000000000000000000..729c5445f6e184998cfc9ba9f02064509e946968 --- /dev/null +++ b/app/src/main/res/drawable/bg_type.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/btn_blue_selector.xml b/app/src/main/res/drawable/btn_blue_selector.xml deleted file mode 100644 index 357836aca9c94ada366d833a312fc16bb3df8bc7..0000000000000000000000000000000000000000 --- a/app/src/main/res/drawable/btn_blue_selector.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/btn_clear_input_selector.xml b/app/src/main/res/drawable/btn_clear_input_selector.xml deleted file mode 100644 index 02f84e83afbe34412dbc881cdc34547caa6f1125..0000000000000000000000000000000000000000 --- a/app/src/main/res/drawable/btn_clear_input_selector.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/btn_emoji_selector.xml b/app/src/main/res/drawable/btn_emoji_selector.xml index 038b7ac23b599ce7000a3cd523cc8c3d75b1fe1d..2c8db2795d92fae0e3577e75648df70e34cbd41d 100644 --- a/app/src/main/res/drawable/btn_emoji_selector.xml +++ b/app/src/main/res/drawable/btn_emoji_selector.xml @@ -1,7 +1,8 @@ - - + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/btn_item_opt_more_selector.xml b/app/src/main/res/drawable/btn_item_opt_more_selector.xml deleted file mode 100644 index b2ecd0990e46b1c22c8409f925d61abb3444a882..0000000000000000000000000000000000000000 --- a/app/src/main/res/drawable/btn_item_opt_more_selector.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/btn_opt_text_to_tools_selector.xml b/app/src/main/res/drawable/btn_opt_text_to_tools_selector.xml index 385e145676ed32276493d576dd9bc911270c0171..e1d880c1310965b76ef02c7066c4cedbefbf1f07 100644 --- a/app/src/main/res/drawable/btn_opt_text_to_tools_selector.xml +++ b/app/src/main/res/drawable/btn_opt_text_to_tools_selector.xml @@ -1,7 +1,7 @@ - - + + \ No newline at end of file diff --git a/app/src/main/res/drawable/btn_opt_tools_to_text_selector.xml b/app/src/main/res/drawable/btn_opt_tools_to_text_selector.xml index adc7dc01552ca144b36d5d978b090d4679ee1e29..e294d385a07d56c0452841a7800551f2bdc52104 100644 --- a/app/src/main/res/drawable/btn_opt_tools_to_text_selector.xml +++ b/app/src/main/res/drawable/btn_opt_tools_to_text_selector.xml @@ -1,7 +1,7 @@ - - + + \ No newline at end of file diff --git a/app/src/main/res/drawable/btn_pic_selector.xml b/app/src/main/res/drawable/btn_pic_selector.xml new file mode 100644 index 0000000000000000000000000000000000000000..4504734c4056284b26183bcfe906d7cf76d369e9 --- /dev/null +++ b/app/src/main/res/drawable/btn_pic_selector.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/btn_quickoption_selector.xml b/app/src/main/res/drawable/btn_quickoption_selector.xml deleted file mode 100644 index 2b5bb61b435e8cecc562c9b45b3fed191be87924..0000000000000000000000000000000000000000 --- a/app/src/main/res/drawable/btn_quickoption_selector.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/btn_radio_selector.xml b/app/src/main/res/drawable/btn_radio_selector.xml index 657e1f3d9a7cd970f84d6d3d066ee26edf483efa..7ea0b6fb221f805b4f1bfb136e7db92d7e7be72f 100644 --- a/app/src/main/res/drawable/btn_radio_selector.xml +++ b/app/src/main/res/drawable/btn_radio_selector.xml @@ -17,43 +17,43 @@ + android:drawable="@mipmap/btn_radio_on" /> + android:drawable="@mipmap/btn_radio_off" /> + android:drawable="@mipmap/btn_radio_on" /> + android:drawable="@mipmap/btn_radio_off" /> + android:drawable="@mipmap/btn_radio_on" /> + android:drawable="@mipmap/btn_radio_off" /> + android:drawable="@mipmap/btn_radio_off" /> + android:drawable="@mipmap/btn_radio_on" /> + android:drawable="@mipmap/btn_radio_on" /> + android:drawable="@mipmap/btn_radio_off" /> + android:drawable="@mipmap/btn_radio_on" /> + android:drawable="@mipmap/btn_radio_off" /> - - + + diff --git a/app/src/main/res/drawable/btn_select_image_done_bg_selector.xml b/app/src/main/res/drawable/btn_select_image_done_bg_selector.xml new file mode 100644 index 0000000000000000000000000000000000000000..eee12a456f75ffd53085815e4d1fd5025dd7158b --- /dev/null +++ b/app/src/main/res/drawable/btn_select_image_done_bg_selector.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/btn_select_image_preview_bg_selector.xml b/app/src/main/res/drawable/btn_select_image_preview_bg_selector.xml new file mode 100644 index 0000000000000000000000000000000000000000..8c8a12c46461737306450c81de1b6f999a3bb96a --- /dev/null +++ b/app/src/main/res/drawable/btn_select_image_preview_bg_selector.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/btn_send_comment_selector.xml b/app/src/main/res/drawable/btn_send_comment_selector.xml deleted file mode 100644 index 7e08ef6bc4855e80ec0d4d3b41f8d2d535cee9cc..0000000000000000000000000000000000000000 --- a/app/src/main/res/drawable/btn_send_comment_selector.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/btn_small_green_selector.xml b/app/src/main/res/drawable/btn_small_green_selector.xml deleted file mode 100644 index 6cdb2596b7aadbbf9f8d5e8fd3f39db66ec37eb4..0000000000000000000000000000000000000000 --- a/app/src/main/res/drawable/btn_small_green_selector.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/btn_small_white_selector.xml b/app/src/main/res/drawable/btn_small_white_selector.xml deleted file mode 100644 index 348e931179e89b024825106be39a7702f7f5f3d9..0000000000000000000000000000000000000000 --- a/app/src/main/res/drawable/btn_small_white_selector.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/btn_software_bg.xml b/app/src/main/res/drawable/btn_software_bg.xml new file mode 100644 index 0000000000000000000000000000000000000000..c917b8c032e48d222315061f3f607f09051a21ae --- /dev/null +++ b/app/src/main/res/drawable/btn_software_bg.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/btn_white_selector.xml b/app/src/main/res/drawable/btn_white_selector.xml deleted file mode 100644 index 731f519a669db5df0d910bdc5dc5b0e40cea867c..0000000000000000000000000000000000000000 --- a/app/src/main/res/drawable/btn_white_selector.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/cb_select_image_check_selector.xml b/app/src/main/res/drawable/cb_select_image_check_selector.xml new file mode 100644 index 0000000000000000000000000000000000000000..4d5cfceb40d9630e21a6f5850ee76af524e7f63f --- /dev/null +++ b/app/src/main/res/drawable/cb_select_image_check_selector.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/chat_from_bg_selector.xml b/app/src/main/res/drawable/chat_from_bg_selector.xml index 0408b6677ae916975d8fb109284c3e0a4bdbf008..1a1dfc3242c6e394f1524ebbdc26d89ae3fd1fbe 100644 --- a/app/src/main/res/drawable/chat_from_bg_selector.xml +++ b/app/src/main/res/drawable/chat_from_bg_selector.xml @@ -1,6 +1,6 @@ - - - + + + diff --git a/app/src/main/res/drawable/chat_to_bg_selector.xml b/app/src/main/res/drawable/chat_to_bg_selector.xml index 3affac8b8c7aa00d842aaff2abe5c35d67679d85..1eb36fd6fbe89acade1756688c7bda22e2270a0a 100644 --- a/app/src/main/res/drawable/chat_to_bg_selector.xml +++ b/app/src/main/res/drawable/chat_to_bg_selector.xml @@ -1,6 +1,6 @@ - - - + + + diff --git a/app/src/main/res/drawable/comment_edittext_selector.xml b/app/src/main/res/drawable/comment_edittext_selector.xml index 69e271b3b98779102982ed804491b390b47d2e70..6a6d36019785c9d2c17d995c82994fca94557e6a 100644 --- a/app/src/main/res/drawable/comment_edittext_selector.xml +++ b/app/src/main/res/drawable/comment_edittext_selector.xml @@ -1,8 +1,8 @@ - - - + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/compose_clear_selector.xml b/app/src/main/res/drawable/compose_clear_selector.xml index 9bd9801fcccd52189ef1c124f1b40c1c481fb377..f875d9365a54e36a28926ccf39097ef75f21be44 100644 --- a/app/src/main/res/drawable/compose_clear_selector.xml +++ b/app/src/main/res/drawable/compose_clear_selector.xml @@ -1,7 +1,7 @@ - - + + \ No newline at end of file diff --git a/app/src/main/res/drawable/compose_toolbar_emoji_selector.xml b/app/src/main/res/drawable/compose_toolbar_emoji_selector.xml index f32b9c9f835d55092592bbee8b20b438872c7b82..3b831fed11b34de164019baf6618b0e762d9d3cb 100644 --- a/app/src/main/res/drawable/compose_toolbar_emoji_selector.xml +++ b/app/src/main/res/drawable/compose_toolbar_emoji_selector.xml @@ -1,7 +1,7 @@ - - + + \ No newline at end of file diff --git a/app/src/main/res/drawable/compose_toolbar_keyboard_selector.xml b/app/src/main/res/drawable/compose_toolbar_keyboard_selector.xml deleted file mode 100644 index be7e83c5e24485af09411432e721a546c6292140..0000000000000000000000000000000000000000 --- a/app/src/main/res/drawable/compose_toolbar_keyboard_selector.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/compose_toolbar_mention_selector.xml b/app/src/main/res/drawable/compose_toolbar_mention_selector.xml index 8df8180800272b4420b3967314b049b29021145c..076ef7186a659aac2d567182707a6b9bb587346f 100644 --- a/app/src/main/res/drawable/compose_toolbar_mention_selector.xml +++ b/app/src/main/res/drawable/compose_toolbar_mention_selector.xml @@ -1,7 +1,7 @@ - - + + \ No newline at end of file diff --git a/app/src/main/res/drawable/compose_toolbar_picture_selector.xml b/app/src/main/res/drawable/compose_toolbar_picture_selector.xml index 9881787f80da9833efaf6d314f9ef138f501a1c4..dd0bb7717670f2fc026b69efb277131cec305cfa 100644 --- a/app/src/main/res/drawable/compose_toolbar_picture_selector.xml +++ b/app/src/main/res/drawable/compose_toolbar_picture_selector.xml @@ -1,7 +1,7 @@ - - + + \ No newline at end of file diff --git a/app/src/main/res/drawable/compose_toolbar_trend_selector.xml b/app/src/main/res/drawable/compose_toolbar_trend_selector.xml index 4a29314e7d908bebb3a3b0ff4d1abdfb0fe83743..209a5d9329fa4987ef6ee1fd038cbc4a71a8841e 100644 --- a/app/src/main/res/drawable/compose_toolbar_trend_selector.xml +++ b/app/src/main/res/drawable/compose_toolbar_trend_selector.xml @@ -1,7 +1,7 @@ - - + + \ No newline at end of file diff --git a/app/src/main/res/drawable/day_quickoption_icon_album_selector.xml b/app/src/main/res/drawable/day_quickoption_icon_album_selector.xml index 687bff3f5e3d9abeef881817118ea4e35a099181..918845f6bac65cc83af9d0981e4732f9206d3dbf 100644 --- a/app/src/main/res/drawable/day_quickoption_icon_album_selector.xml +++ b/app/src/main/res/drawable/day_quickoption_icon_album_selector.xml @@ -1,6 +1,6 @@ - - + + diff --git a/app/src/main/res/drawable/day_quickoption_icon_note_selector.xml b/app/src/main/res/drawable/day_quickoption_icon_note_selector.xml index effc6a6138053b5a90e432b7f4cb8a1d28986632..71836f1d5ffddd844828388841b5e28ed4ab6364 100644 --- a/app/src/main/res/drawable/day_quickoption_icon_note_selector.xml +++ b/app/src/main/res/drawable/day_quickoption_icon_note_selector.xml @@ -1,6 +1,6 @@ - - + + diff --git a/app/src/main/res/drawable/day_quickoption_icon_photo_selector.xml b/app/src/main/res/drawable/day_quickoption_icon_photo_selector.xml index 03bad9aba74ee2f704be472a94054107ba712dfb..820d652eb9e0fb268d7f62087e150068bed4f3ed 100644 --- a/app/src/main/res/drawable/day_quickoption_icon_photo_selector.xml +++ b/app/src/main/res/drawable/day_quickoption_icon_photo_selector.xml @@ -1,6 +1,6 @@ - - + + diff --git a/app/src/main/res/drawable/day_quickoption_icon_scan_selector.xml b/app/src/main/res/drawable/day_quickoption_icon_scan_selector.xml index 648c3b16c648b1779d0a0798ad1fec5a5801412a..3a463d097be23274d6be6b083761c4b160146367 100644 --- a/app/src/main/res/drawable/day_quickoption_icon_scan_selector.xml +++ b/app/src/main/res/drawable/day_quickoption_icon_scan_selector.xml @@ -1,6 +1,6 @@ - - + + diff --git a/app/src/main/res/drawable/day_quickoption_icon_text_selector.xml b/app/src/main/res/drawable/day_quickoption_icon_text_selector.xml index 9c1bcb2f409ed4d8daaf1e1a7a1980f812b5dfd0..edb3b5b075c4de3555658f9c5b495c77bf034a13 100644 --- a/app/src/main/res/drawable/day_quickoption_icon_text_selector.xml +++ b/app/src/main/res/drawable/day_quickoption_icon_text_selector.xml @@ -1,6 +1,6 @@ - - + + diff --git a/app/src/main/res/drawable/day_quickoption_icon_voice_selector.xml b/app/src/main/res/drawable/day_quickoption_icon_voice_selector.xml index 2ced7ac20447017e08976888ce841b43d48b47a6..8ec9b9a166e14302069a10d89ec3dfd8ac90eeca 100644 --- a/app/src/main/res/drawable/day_quickoption_icon_voice_selector.xml +++ b/app/src/main/res/drawable/day_quickoption_icon_voice_selector.xml @@ -1,6 +1,6 @@ - - + + diff --git a/app/src/main/res/drawable/drawer_menu_item_background.xml b/app/src/main/res/drawable/drawer_menu_item_background.xml deleted file mode 100644 index 349cfa958ad0bcee6e8d156a7eef42995bb54dd3..0000000000000000000000000000000000000000 --- a/app/src/main/res/drawable/drawer_menu_item_background.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - diff --git a/app/src/main/res/drawable/ib_clear_image_selector.xml b/app/src/main/res/drawable/ib_clear_image_selector.xml index 458515ea859ed460d0a58a65bb33f620beb927d5..809b6abf226cdaee2ea9210aeb84b8d7e19c18d6 100644 --- a/app/src/main/res/drawable/ib_clear_image_selector.xml +++ b/app/src/main/res/drawable/ib_clear_image_selector.xml @@ -1,7 +1,7 @@ - - + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_action_comment.xml b/app/src/main/res/drawable/ic_action_comment.xml index 6993d6021be8bd501e1bbca9422957d321292d71..eaad1f3b8fdda152399aa5bbde07197c3792191b 100644 --- a/app/src/main/res/drawable/ic_action_comment.xml +++ b/app/src/main/res/drawable/ic_action_comment.xml @@ -1,6 +1,6 @@ - - + + diff --git a/app/src/main/res/drawable/ic_action_favor.xml b/app/src/main/res/drawable/ic_action_favor.xml index 23d67819f9674321c44a194e72ff4b6b7b3673a1..242fe099e81c3a4c059d36fe44d8c1578d624de8 100644 --- a/app/src/main/res/drawable/ic_action_favor.xml +++ b/app/src/main/res/drawable/ic_action_favor.xml @@ -1,8 +1,8 @@ - - - - + + + + diff --git a/app/src/main/res/drawable/ic_action_report.xml b/app/src/main/res/drawable/ic_action_report.xml index f09e584124a2d395790240f4f5dded1e1956f058..19137919cf4aa0ac8f7223c1a7be2255ddf17c7e 100644 --- a/app/src/main/res/drawable/ic_action_report.xml +++ b/app/src/main/res/drawable/ic_action_report.xml @@ -1,6 +1,6 @@ - - + + diff --git a/app/src/main/res/drawable/ic_action_repost.xml b/app/src/main/res/drawable/ic_action_repost.xml index 102684c33ce888e16b2148aae71616abf3a5bce9..5182ecd765df79613b9639e643680a26156f3a5b 100644 --- a/app/src/main/res/drawable/ic_action_repost.xml +++ b/app/src/main/res/drawable/ic_action_repost.xml @@ -1,6 +1,6 @@ - - + + diff --git a/app/src/main/res/drawable/ic_action_write.xml b/app/src/main/res/drawable/ic_action_write.xml index 1088ee04926cecaec14d13b6a27148ebccf9d616..76015661181709a44c4397dfa29d1b1a5be0368e 100644 --- a/app/src/main/res/drawable/ic_action_write.xml +++ b/app/src/main/res/drawable/ic_action_write.xml @@ -1,6 +1,6 @@ - - + + diff --git a/app/src/main/res/drawable/ic_bg_btn_blue.xml b/app/src/main/res/drawable/ic_bg_btn_blue.xml new file mode 100644 index 0000000000000000000000000000000000000000..ddc16a9378dde6ecbf444f40ed551e8d00958290 --- /dev/null +++ b/app/src/main/res/drawable/ic_bg_btn_blue.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/social_sdk_library_project/src/main/res/drawable/btn_red_pressed.xml b/app/src/main/res/drawable/ic_bg_btn_blue_active.xml similarity index 50% rename from social_sdk_library_project/src/main/res/drawable/btn_red_pressed.xml rename to app/src/main/res/drawable/ic_bg_btn_blue_active.xml index 7a6c9b65f8690fc9d36fe4f15f88525677ae0cc9..f1667d35a0714eb4cae964b100f44e39a2131455 100644 --- a/social_sdk_library_project/src/main/res/drawable/btn_red_pressed.xml +++ b/app/src/main/res/drawable/ic_bg_btn_blue_active.xml @@ -1,6 +1,5 @@ - - - + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_bg_btn_blue_normal.xml b/app/src/main/res/drawable/ic_bg_btn_blue_normal.xml new file mode 100644 index 0000000000000000000000000000000000000000..0f27cb444f43acd8d1181873388c6125a2c5d802 --- /dev/null +++ b/app/src/main/res/drawable/ic_bg_btn_blue_normal.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_bg_btn_blue_unavailable.xml b/app/src/main/res/drawable/ic_bg_btn_blue_unavailable.xml new file mode 100644 index 0000000000000000000000000000000000000000..1b68d0c0ec8a81f6924f5f27c8f91d17f75f04a8 --- /dev/null +++ b/app/src/main/res/drawable/ic_bg_btn_blue_unavailable.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_bg_edit.xml b/app/src/main/res/drawable/ic_bg_edit.xml new file mode 100644 index 0000000000000000000000000000000000000000..5ad1c3bf2a2641e8a2231f9ef1aaef1d6a6568b1 --- /dev/null +++ b/app/src/main/res/drawable/ic_bg_edit.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/btn_oval_background.xml b/app/src/main/res/drawable/ic_bg_edit_active.xml similarity index 71% rename from app/src/main/res/drawable/btn_oval_background.xml rename to app/src/main/res/drawable/ic_bg_edit_active.xml index 667f1305cefdf042b019c3886f00b38f038c3653..cdd93ed02e7ee6e06b1ce192229a84419ac5dc77 100644 --- a/app/src/main/res/drawable/btn_oval_background.xml +++ b/app/src/main/res/drawable/ic_bg_edit_active.xml @@ -1,12 +1,8 @@ - - - - + - - - + android:color="#24cf5f" /> + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_bg_edit_normal.xml b/app/src/main/res/drawable/ic_bg_edit_normal.xml new file mode 100644 index 0000000000000000000000000000000000000000..15a550383fd1a7f29d88fc25b7a9c03a432019c6 --- /dev/null +++ b/app/src/main/res/drawable/ic_bg_edit_normal.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_comment_40_selector.xml b/app/src/main/res/drawable/ic_comment_40_selector.xml new file mode 100644 index 0000000000000000000000000000000000000000..ac8badd1897ffd5bec5989dec04853f87039c8a9 --- /dev/null +++ b/app/src/main/res/drawable/ic_comment_40_selector.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_fav.xml b/app/src/main/res/drawable/ic_fav.xml new file mode 100644 index 0000000000000000000000000000000000000000..9779e09f50de668887f9a9be9f00fafd3f43ba2d --- /dev/null +++ b/app/src/main/res/drawable/ic_fav.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_faved.xml b/app/src/main/res/drawable/ic_faved.xml new file mode 100644 index 0000000000000000000000000000000000000000..a58c4e440e05f7d44d468d8f509572c4962faddd --- /dev/null +++ b/app/src/main/res/drawable/ic_faved.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_material.xml b/app/src/main/res/drawable/ic_material.xml new file mode 100644 index 0000000000000000000000000000000000000000..bea787b9bc653e845c93ed3319c90f221939117a --- /dev/null +++ b/app/src/main/res/drawable/ic_material.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_nav_add_actived.xml b/app/src/main/res/drawable/ic_nav_add_actived.xml new file mode 100644 index 0000000000000000000000000000000000000000..7c9c02196c4c28263d713a5ab8bfe51e37e3489b --- /dev/null +++ b/app/src/main/res/drawable/ic_nav_add_actived.xml @@ -0,0 +1,26 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_nav_add_normal.xml b/app/src/main/res/drawable/ic_nav_add_normal.xml new file mode 100644 index 0000000000000000000000000000000000000000..9b3a730032f8f72196ee4709e937c4cc0053931a --- /dev/null +++ b/app/src/main/res/drawable/ic_nav_add_normal.xml @@ -0,0 +1,21 @@ + + + + + diff --git a/app/src/main/res/drawable/btn_del_selector.xml b/app/src/main/res/drawable/ic_nav_add_selector.xml similarity index 36% rename from app/src/main/res/drawable/btn_del_selector.xml rename to app/src/main/res/drawable/ic_nav_add_selector.xml index dc0055c6451e4a1db07621ee277dc6984ec016ff..24ed84487576f3c3e426cf519ef2b43607094fce 100644 --- a/app/src/main/res/drawable/btn_del_selector.xml +++ b/app/src/main/res/drawable/ic_nav_add_selector.xml @@ -1,7 +1,7 @@ - - + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_red_dot.xml b/app/src/main/res/drawable/ic_red_dot.xml new file mode 100644 index 0000000000000000000000000000000000000000..555150975c16c43d998936ce8ce6a835caf5a2d0 --- /dev/null +++ b/app/src/main/res/drawable/ic_red_dot.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_selector_checkbox.xml b/app/src/main/res/drawable/ic_selector_checkbox.xml new file mode 100644 index 0000000000000000000000000000000000000000..470ff4d7cfe0e29aba19f1527ed2425d54b48b45 --- /dev/null +++ b/app/src/main/res/drawable/ic_selector_checkbox.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_share_black.xml b/app/src/main/res/drawable/ic_share_black.xml new file mode 100644 index 0000000000000000000000000000000000000000..2164dbb8934d50ec389c28b586e6b41c5beda72f --- /dev/null +++ b/app/src/main/res/drawable/ic_share_black.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_tweet_indicator_selector.xml b/app/src/main/res/drawable/ic_tweet_indicator_selector.xml new file mode 100644 index 0000000000000000000000000000000000000000..63c251fac013737d0dceaf9ee89ece888b257315 --- /dev/null +++ b/app/src/main/res/drawable/ic_tweet_indicator_selector.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/item_blog_about_bg_selector.xml b/app/src/main/res/drawable/item_blog_about_bg_selector.xml new file mode 100644 index 0000000000000000000000000000000000000000..be067d813236a147b261fdc3f6665abba1ecaf79 --- /dev/null +++ b/app/src/main/res/drawable/item_blog_about_bg_selector.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/item_selector.xml b/app/src/main/res/drawable/item_selector.xml new file mode 100644 index 0000000000000000000000000000000000000000..bea787b9bc653e845c93ed3319c90f221939117a --- /dev/null +++ b/app/src/main/res/drawable/item_selector.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/messages_left_bubble_selector.xml b/app/src/main/res/drawable/messages_left_bubble_selector.xml deleted file mode 100644 index e913b22b93e1803bf2f443c54540afec5a897d94..0000000000000000000000000000000000000000 --- a/app/src/main/res/drawable/messages_left_bubble_selector.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/night_quickoption_icon_album_selector.xml b/app/src/main/res/drawable/night_quickoption_icon_album_selector.xml index 299fe6ee9fc6359ace767a0d9ba123fc2d7ff481..49140ddf04ae74864c53f37076cfc8b5ce289dad 100644 --- a/app/src/main/res/drawable/night_quickoption_icon_album_selector.xml +++ b/app/src/main/res/drawable/night_quickoption_icon_album_selector.xml @@ -1,6 +1,6 @@ - - + + diff --git a/app/src/main/res/drawable/night_quickoption_icon_note_selector.xml b/app/src/main/res/drawable/night_quickoption_icon_note_selector.xml index 697072e1ab43efa2190e6fa266f89659287be74e..1c5eecec42b0d364003a2609b6a3c3c1a099a6b8 100644 --- a/app/src/main/res/drawable/night_quickoption_icon_note_selector.xml +++ b/app/src/main/res/drawable/night_quickoption_icon_note_selector.xml @@ -1,6 +1,6 @@ - - + + diff --git a/app/src/main/res/drawable/night_quickoption_icon_photo_selector.xml b/app/src/main/res/drawable/night_quickoption_icon_photo_selector.xml index 6c789f2df501d7d7acf660e47f158be75cc1f8e1..98c6f9be637c439cc948109a147e73d4fa8b064e 100644 --- a/app/src/main/res/drawable/night_quickoption_icon_photo_selector.xml +++ b/app/src/main/res/drawable/night_quickoption_icon_photo_selector.xml @@ -1,6 +1,6 @@ - - + + diff --git a/app/src/main/res/drawable/night_quickoption_icon_scan_selector.xml b/app/src/main/res/drawable/night_quickoption_icon_scan_selector.xml index 3080b7f6af8bd68bf998a0559e8173ef435f7179..35007d96037cc7bab8747e588ade5a3c6f21edc2 100644 --- a/app/src/main/res/drawable/night_quickoption_icon_scan_selector.xml +++ b/app/src/main/res/drawable/night_quickoption_icon_scan_selector.xml @@ -1,6 +1,6 @@ - - + + diff --git a/app/src/main/res/drawable/night_quickoption_icon_text_selector.xml b/app/src/main/res/drawable/night_quickoption_icon_text_selector.xml index 1a20612397df648534ead7ed61b690928f35fc68..35b07e64de01f36af32761301d01d0ed274c2c55 100644 --- a/app/src/main/res/drawable/night_quickoption_icon_text_selector.xml +++ b/app/src/main/res/drawable/night_quickoption_icon_text_selector.xml @@ -1,6 +1,6 @@ - - + + diff --git a/app/src/main/res/drawable/night_quickoption_icon_voice_selector.xml b/app/src/main/res/drawable/night_quickoption_icon_voice_selector.xml index 434070d7f9c20892fba3d0bdf8b1e615fef09ad2..b4bb8a0b8ad3587a01a98ee3aac3635b846faffe 100644 --- a/app/src/main/res/drawable/night_quickoption_icon_voice_selector.xml +++ b/app/src/main/res/drawable/night_quickoption_icon_voice_selector.xml @@ -1,6 +1,6 @@ - - + + diff --git a/app/src/main/res/drawable/pic_bg.xml b/app/src/main/res/drawable/pic_bg.xml index 39ef1d88ad6eb03b56d5f1605be48a7182956900..cf151b137cd02cd2c903dbf65171565a5fb21584 100644 --- a/app/src/main/res/drawable/pic_bg.xml +++ b/app/src/main/res/drawable/pic_bg.xml @@ -3,6 +3,10 @@ android:shape="rectangle"> - + + diff --git a/app/src/main/res/drawable/progress_medium_holo.xml b/app/src/main/res/drawable/progress_medium_holo.xml index 6772f584f097387d9a3372b0976bb7e2a452926c..8f257f82e0a26a071e669b4358b7fb47967b6f0c 100644 --- a/app/src/main/res/drawable/progress_medium_holo.xml +++ b/app/src/main/res/drawable/progress_medium_holo.xml @@ -17,7 +17,7 @@ + android:src="@mipmap/loading" /> diff --git a/app/src/main/res/drawable/ques_bt_bg.xml b/app/src/main/res/drawable/ques_bt_bg.xml new file mode 100644 index 0000000000000000000000000000000000000000..250b5b52a8c043c1ded8197d12fc844876d2e664 --- /dev/null +++ b/app/src/main/res/drawable/ques_bt_bg.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/selector_comment.xml b/app/src/main/res/drawable/selector_comment.xml new file mode 100644 index 0000000000000000000000000000000000000000..f2cf80e61449c43d44fc1c569b39ad7bfa8755a8 --- /dev/null +++ b/app/src/main/res/drawable/selector_comment.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_dynamic_tab.xml b/app/src/main/res/drawable/selector_dynamic_tab.xml new file mode 100644 index 0000000000000000000000000000000000000000..4dd03092f26a9069e82c141d29f0486729ec2451 --- /dev/null +++ b/app/src/main/res/drawable/selector_dynamic_tab.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_event_fav.xml b/app/src/main/res/drawable/selector_event_fav.xml new file mode 100644 index 0000000000000000000000000000000000000000..3594e927c70913bebcf3812297995fafd6a51e9b --- /dev/null +++ b/app/src/main/res/drawable/selector_event_fav.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_event_sign.xml b/app/src/main/res/drawable/selector_event_sign.xml new file mode 100644 index 0000000000000000000000000000000000000000..76711f0ec6fe83fabb8f07e8797c8b729900b279 --- /dev/null +++ b/app/src/main/res/drawable/selector_event_sign.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_event_sign_up.xml b/app/src/main/res/drawable/selector_event_sign_up.xml new file mode 100644 index 0000000000000000000000000000000000000000..7b2875115bfd2283a6f7666fd44bb67030a0367c --- /dev/null +++ b/app/src/main/res/drawable/selector_event_sign_up.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_full_vote_down.xml b/app/src/main/res/drawable/selector_full_vote_down.xml new file mode 100644 index 0000000000000000000000000000000000000000..201f8040eb6a9c2410fa72fa81eaa1ae215feb19 --- /dev/null +++ b/app/src/main/res/drawable/selector_full_vote_down.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_full_vote_up.xml b/app/src/main/res/drawable/selector_full_vote_up.xml new file mode 100644 index 0000000000000000000000000000000000000000..face9f8bd266f047a54b2a196601d369ff0e01e6 --- /dev/null +++ b/app/src/main/res/drawable/selector_full_vote_up.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_item_list.xml b/app/src/main/res/drawable/selector_item_list.xml new file mode 100644 index 0000000000000000000000000000000000000000..bea787b9bc653e845c93ed3319c90f221939117a --- /dev/null +++ b/app/src/main/res/drawable/selector_item_list.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_keyboard.xml b/app/src/main/res/drawable/selector_keyboard.xml index e27385f1f6ead85115881a08bdd2ae1be7d1d2c9..330b2ae44234168dbb2d9e54ee72b646d189522d 100644 --- a/app/src/main/res/drawable/selector_keyboard.xml +++ b/app/src/main/res/drawable/selector_keyboard.xml @@ -1,5 +1,5 @@ - - + + diff --git a/app/src/main/res/drawable/selector_nav_back_light.xml b/app/src/main/res/drawable/selector_nav_back_light.xml new file mode 100644 index 0000000000000000000000000000000000000000..92aa9ebad3a45d2d962f561c7a1fa298ed438ac7 --- /dev/null +++ b/app/src/main/res/drawable/selector_nav_back_light.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_nav_back_night.xml b/app/src/main/res/drawable/selector_nav_back_night.xml new file mode 100644 index 0000000000000000000000000000000000000000..2ea22a570fd6e991dfd24f7674c82cf626344515 --- /dev/null +++ b/app/src/main/res/drawable/selector_nav_back_night.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_other_user_left_half_wrapper.xml b/app/src/main/res/drawable/selector_other_user_left_half_wrapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..ee2f106eff4a61446247d6d1aadc28d04ae6b66c --- /dev/null +++ b/app/src/main/res/drawable/selector_other_user_left_half_wrapper.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_other_user_right_half_wrapper.xml b/app/src/main/res/drawable/selector_other_user_right_half_wrapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..1ed4d28f42ddd398aa6b87931e09c0cb3df71f0d --- /dev/null +++ b/app/src/main/res/drawable/selector_other_user_right_half_wrapper.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_pay_btn.xml b/app/src/main/res/drawable/selector_pay_btn.xml new file mode 100644 index 0000000000000000000000000000000000000000..1fdb086353f68a076fa817eb237aa9d2b4162ce7 --- /dev/null +++ b/app/src/main/res/drawable/selector_pay_btn.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_pay_input.xml b/app/src/main/res/drawable/selector_pay_input.xml new file mode 100644 index 0000000000000000000000000000000000000000..94ca3536795ffc950dde2c5fe778e25a04dd0d83 --- /dev/null +++ b/app/src/main/res/drawable/selector_pay_input.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/social_sdk_library_project/src/main/res/drawable/umeng_socialize_oauth_check.xml b/app/src/main/res/drawable/selector_pay_text.xml similarity index 37% rename from social_sdk_library_project/src/main/res/drawable/umeng_socialize_oauth_check.xml rename to app/src/main/res/drawable/selector_pay_text.xml index c14d422a3a15aee77f168162e4c8d9da138eac3c..8754e8c04dd14a7f314e21d3d1f787ba3f535ef3 100644 --- a/social_sdk_library_project/src/main/res/drawable/umeng_socialize_oauth_check.xml +++ b/app/src/main/res/drawable/selector_pay_text.xml @@ -1,7 +1,10 @@ - - + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_record_layout.xml b/app/src/main/res/drawable/selector_record_layout.xml index c905bdc7a6b3881b2273852af1091b0f27f396e3..5bad081f775475fc7183558906f9631538b72424 100644 --- a/app/src/main/res/drawable/selector_record_layout.xml +++ b/app/src/main/res/drawable/selector_record_layout.xml @@ -1,7 +1,7 @@ - - + + \ No newline at end of file diff --git a/social_sdk_library_project/src/main/res/drawable/umeng_socialize_follow_check.xml b/app/src/main/res/drawable/selector_reward_btn.xml similarity index 38% rename from social_sdk_library_project/src/main/res/drawable/umeng_socialize_follow_check.xml rename to app/src/main/res/drawable/selector_reward_btn.xml index 3af06f240a8068d062f0b2271c65079f71953a2c..1cd29b737bdb52909fea1e23e5b94b10f6c88b09 100644 --- a/social_sdk_library_project/src/main/res/drawable/umeng_socialize_follow_check.xml +++ b/app/src/main/res/drawable/selector_reward_btn.xml @@ -1,7 +1,7 @@ - - + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_send.xml b/app/src/main/res/drawable/selector_send.xml index e4c189d087bf3c26256622227ebec9b6a7f18ff7..bb5c288f7bcfb3ea37a0791540258409f5a0ebec 100644 --- a/app/src/main/res/drawable/selector_send.xml +++ b/app/src/main/res/drawable/selector_send.xml @@ -1,5 +1,5 @@ - - + + diff --git a/app/src/main/res/drawable/selector_shake_again.xml b/app/src/main/res/drawable/selector_shake_again.xml new file mode 100644 index 0000000000000000000000000000000000000000..1f95d32360f30a20aab40349a6bb8111e67f0b0c --- /dev/null +++ b/app/src/main/res/drawable/selector_shake_again.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_shake_get.xml b/app/src/main/res/drawable/selector_shake_get.xml new file mode 100644 index 0000000000000000000000000000000000000000..c5f72fdecb2f209c7e97a3da7e011b08ce32ede7 --- /dev/null +++ b/app/src/main/res/drawable/selector_shake_get.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_shake_news.xml b/app/src/main/res/drawable/selector_shake_news.xml new file mode 100644 index 0000000000000000000000000000000000000000..3fe1b9bdd52f3d3630e9b1c8cb6b1d4286952386 --- /dev/null +++ b/app/src/main/res/drawable/selector_shake_news.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_shake_present.xml b/app/src/main/res/drawable/selector_shake_present.xml new file mode 100644 index 0000000000000000000000000000000000000000..e182ad5549631fc6cdda55b5f15902ca9157658c --- /dev/null +++ b/app/src/main/res/drawable/selector_shake_present.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_sign.xml b/app/src/main/res/drawable/selector_sign.xml new file mode 100644 index 0000000000000000000000000000000000000000..b9aa1de29e56da28f8dee4fffaf16e851378f286 --- /dev/null +++ b/app/src/main/res/drawable/selector_sign.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_tab_item_other_user.xml b/app/src/main/res/drawable/selector_tab_item_other_user.xml new file mode 100644 index 0000000000000000000000000000000000000000..3ef0bb04ac67f1c6553ab5a073e37a7580917b14 --- /dev/null +++ b/app/src/main/res/drawable/selector_tab_item_other_user.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_thumb.xml b/app/src/main/res/drawable/selector_thumb.xml new file mode 100644 index 0000000000000000000000000000000000000000..7c50fc0368dfb6fdf25ba71212a623064e2198eb --- /dev/null +++ b/app/src/main/res/drawable/selector_thumb.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_user_follow.xml b/app/src/main/res/drawable/selector_user_follow.xml new file mode 100644 index 0000000000000000000000000000000000000000..43f1c11621e39c80e9969bec933fcc264a64548e --- /dev/null +++ b/app/src/main/res/drawable/selector_user_follow.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_user_following.xml b/app/src/main/res/drawable/selector_user_following.xml new file mode 100644 index 0000000000000000000000000000000000000000..366d6fbe54e73b57d5982c83cb0a716427531446 --- /dev/null +++ b/app/src/main/res/drawable/selector_user_following.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_user_following_botn.xml b/app/src/main/res/drawable/selector_user_following_botn.xml new file mode 100644 index 0000000000000000000000000000000000000000..a2fb2ff67550e3e2df106f1596d6bb81f32b60cf --- /dev/null +++ b/app/src/main/res/drawable/selector_user_following_botn.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/my_infomation_option_item_background.xml b/app/src/main/res/drawable/selector_user_info_tab_item.xml similarity index 36% rename from app/src/main/res/drawable/my_infomation_option_item_background.xml rename to app/src/main/res/drawable/selector_user_info_tab_item.xml index 273ca4dcc44e60c1bff26c6d89ef71938f2dee43..20108219e51bb4ba603e09f15ba207553be29c6b 100644 --- a/app/src/main/res/drawable/my_infomation_option_item_background.xml +++ b/app/src/main/res/drawable/selector_user_info_tab_item.xml @@ -1,8 +1,6 @@ - - - - + + diff --git a/app/src/main/res/drawable/selector_user_pm.xml b/app/src/main/res/drawable/selector_user_pm.xml new file mode 100644 index 0000000000000000000000000000000000000000..b93a4c7ec35261f3637683d8e82920819108668d --- /dev/null +++ b/app/src/main/res/drawable/selector_user_pm.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_vote_down.xml b/app/src/main/res/drawable/selector_vote_down.xml new file mode 100644 index 0000000000000000000000000000000000000000..c5a8ddac0bfaa99d935a51dca583826474f52206 --- /dev/null +++ b/app/src/main/res/drawable/selector_vote_down.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_vote_up.xml b/app/src/main/res/drawable/selector_vote_up.xml new file mode 100644 index 0000000000000000000000000000000000000000..0c30773b57e2010a2e29b42cc14f11cc3a1e3e3b --- /dev/null +++ b/app/src/main/res/drawable/selector_vote_up.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shake_img_border.xml b/app/src/main/res/drawable/shake_img_border.xml new file mode 100644 index 0000000000000000000000000000000000000000..f3cdb66734446a95b5a9edd092746b4d3e264bd3 --- /dev/null +++ b/app/src/main/res/drawable/shake_img_border.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_border_primary.xml b/app/src/main/res/drawable/shape_border_primary.xml new file mode 100644 index 0000000000000000000000000000000000000000..ecf0b88e4c221e7b94116a88b1e34504a7f02b28 --- /dev/null +++ b/app/src/main/res/drawable/shape_border_primary.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_bubble.xml b/app/src/main/res/drawable/shape_bubble.xml new file mode 100644 index 0000000000000000000000000000000000000000..79fe55e48895dc3d004544c9dc3033f8cf54401c --- /dev/null +++ b/app/src/main/res/drawable/shape_bubble.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_gradient.xml b/app/src/main/res/drawable/shape_gradient.xml new file mode 100644 index 0000000000000000000000000000000000000000..fbc72fd5fbf29ac5749989594e1cebf1e59d8425 --- /dev/null +++ b/app/src/main/res/drawable/shape_gradient.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_other_user_wrapper.xml b/app/src/main/res/drawable/shape_other_user_wrapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..20e6a16206a112b695722b0aaa9311b186c7a0ee --- /dev/null +++ b/app/src/main/res/drawable/shape_other_user_wrapper.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_search_view.xml b/app/src/main/res/drawable/shape_search_view.xml new file mode 100644 index 0000000000000000000000000000000000000000..f37e1f96979a587c23f6e1012a716819d244e18a --- /dev/null +++ b/app/src/main/res/drawable/shape_search_view.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/share_bt_selector.xml b/app/src/main/res/drawable/share_bt_selector.xml new file mode 100644 index 0000000000000000000000000000000000000000..3a219935186eb5dd9563b0f463ed35054e8b7bf7 --- /dev/null +++ b/app/src/main/res/drawable/share_bt_selector.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/share_ic_selector.xml b/app/src/main/res/drawable/share_ic_selector.xml new file mode 100644 index 0000000000000000000000000000000000000000..21a7ef52008fb37c52a3d9641ea88a0bfd212285 --- /dev/null +++ b/app/src/main/res/drawable/share_ic_selector.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/share_icon_copy_link_selector.xml b/app/src/main/res/drawable/share_icon_copy_link_selector.xml index fa11e463115e22751b9f69dba5349c998d12d41b..b4f032d207d225648648985865882726d0207d81 100644 --- a/app/src/main/res/drawable/share_icon_copy_link_selector.xml +++ b/app/src/main/res/drawable/share_icon_copy_link_selector.xml @@ -1,6 +1,6 @@ - - + + diff --git a/app/src/main/res/drawable/share_icon_more_selector.xml b/app/src/main/res/drawable/share_icon_more_selector.xml index f046c9bcb57b2e9e3d0c6d14353298fc30043d26..7e1ad831bd97eb3cac21826980ed85527d42a33c 100644 --- a/app/src/main/res/drawable/share_icon_more_selector.xml +++ b/app/src/main/res/drawable/share_icon_more_selector.xml @@ -1,6 +1,6 @@ - - + + diff --git a/app/src/main/res/drawable/share_icon_qq_selector.xml b/app/src/main/res/drawable/share_icon_qq_selector.xml index b36467c1d5f45d14f9b3ee0fb1881b5b3cc033cb..8d544aa2ad6e8de6a2c76317c2a955a58d5021ea 100644 --- a/app/src/main/res/drawable/share_icon_qq_selector.xml +++ b/app/src/main/res/drawable/share_icon_qq_selector.xml @@ -1,6 +1,6 @@ - - + + diff --git a/app/src/main/res/drawable/share_icon_sinaweibo_selector.xml b/app/src/main/res/drawable/share_icon_sinaweibo_selector.xml index 39e41ddafec6a5a1ad6b2a5ecbc3ad4bc35e2b9a..4becb3e3ce85b2e6e9303a7be62e894217986a3f 100644 --- a/app/src/main/res/drawable/share_icon_sinaweibo_selector.xml +++ b/app/src/main/res/drawable/share_icon_sinaweibo_selector.xml @@ -1,6 +1,6 @@ - - + + diff --git a/app/src/main/res/drawable/share_icon_wechat_selector.xml b/app/src/main/res/drawable/share_icon_wechat_selector.xml index 13f78f2fc6a74cc09f606eef662d815f8f689c54..13a8630e3bdf637e0c96bdb98a7fbf6c93890d36 100644 --- a/app/src/main/res/drawable/share_icon_wechat_selector.xml +++ b/app/src/main/res/drawable/share_icon_wechat_selector.xml @@ -1,6 +1,6 @@ - - + + diff --git a/app/src/main/res/drawable/share_icon_wechatfriends_selector.xml b/app/src/main/res/drawable/share_icon_wechatfriends_selector.xml index 402875fa726eeb2cd9f0658de470ba6b9cf70929..fb9eec2f16af95f4156312e4864322540ba42d8e 100644 --- a/app/src/main/res/drawable/share_icon_wechatfriends_selector.xml +++ b/app/src/main/res/drawable/share_icon_wechatfriends_selector.xml @@ -1,6 +1,6 @@ - - + + diff --git a/app/src/main/res/drawable/tab_icon_explore.xml b/app/src/main/res/drawable/tab_icon_explore.xml index bcd249ad635ae6843975bbde7beb20a5d7673c83..13627b437adeba051745eb8de8c29e8372fac92a 100644 --- a/app/src/main/res/drawable/tab_icon_explore.xml +++ b/app/src/main/res/drawable/tab_icon_explore.xml @@ -1,8 +1,7 @@ - - - - - + + + + + diff --git a/app/src/main/res/drawable/tab_icon_me.xml b/app/src/main/res/drawable/tab_icon_me.xml index 7374f7943881e6d7fbe152452db27737570b8150..5eef85402f9edc69e7c95b00c047bd581e4663fd 100644 --- a/app/src/main/res/drawable/tab_icon_me.xml +++ b/app/src/main/res/drawable/tab_icon_me.xml @@ -1,8 +1,7 @@ - - - - - + + + + + diff --git a/app/src/main/res/drawable/tab_icon_new.xml b/app/src/main/res/drawable/tab_icon_new.xml index 55ab09e6f3eba79ee70707ef267bc0b85834d225..0798560111a207674d1fa0580030b13800d94db8 100644 --- a/app/src/main/res/drawable/tab_icon_new.xml +++ b/app/src/main/res/drawable/tab_icon_new.xml @@ -1,8 +1,8 @@ - - - - + + + + diff --git a/app/src/main/res/drawable/tab_icon_tweet.xml b/app/src/main/res/drawable/tab_icon_tweet.xml index c134c8425b33f8e5c6cfbaabd9548c353a17e1ac..6c04b2f4866d20b02b3fc54ddd9901a97934c036 100644 --- a/app/src/main/res/drawable/tab_icon_tweet.xml +++ b/app/src/main/res/drawable/tab_icon_tweet.xml @@ -1,8 +1,7 @@ - - - - - + + + + + diff --git a/app/src/main/res/drawable/teamlist_item_background.xml b/app/src/main/res/drawable/teamlist_item_background.xml deleted file mode 100644 index 86d6c148d42dc14cc63f5e14ba39531cba17b6be..0000000000000000000000000000000000000000 --- a/app/src/main/res/drawable/teamlist_item_background.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - diff --git a/app/src/main/res/drawable/textfield_selector.xml b/app/src/main/res/drawable/textfield_selector.xml deleted file mode 100644 index 8ac9b66e59699dc66835a1f989711683ff7c923c..0000000000000000000000000000000000000000 --- a/app/src/main/res/drawable/textfield_selector.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout-v19/lay_tweet_publish_title.xml b/app/src/main/res/layout-v19/lay_tweet_publish_title.xml new file mode 100644 index 0000000000000000000000000000000000000000..472a65e5ef6d2411e0b6e26b7c686b6755dc8711 --- /dev/null +++ b/app/src/main/res/layout-v19/lay_tweet_publish_title.xml @@ -0,0 +1,47 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/actionbar_main_layout.xml b/app/src/main/res/layout/actionbar_main_layout.xml new file mode 100644 index 0000000000000000000000000000000000000000..b477273134827c0aceda0813af004a24858638b8 --- /dev/null +++ b/app/src/main/res/layout/actionbar_main_layout.xml @@ -0,0 +1,24 @@ + + + + + + + diff --git a/app/src/main/res/layout/item_team_select.xml b/app/src/main/res/layout/activity_base_recycler.xml similarity index 36% rename from app/src/main/res/layout/item_team_select.xml rename to app/src/main/res/layout/activity_base_recycler.xml index 86e14f94ba1c703c7f641ddeca8cf8b079afbcc0..59dd2e8770338dd7abd874ea7bf4f86f208d7908 100644 --- a/app/src/main/res/layout/item_team_select.xml +++ b/app/src/main/res/layout/activity_base_recycler.xml @@ -1,16 +1,13 @@ - + android:background="@color/white"> - - - \ No newline at end of file + android:scrollbars="vertical" /> + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_blog_detail.xml b/app/src/main/res/layout/activity_blog_detail.xml new file mode 100644 index 0000000000000000000000000000000000000000..ca232a62f626eec7ffbf3b80117305a92cfa3b73 --- /dev/null +++ b/app/src/main/res/layout/activity_blog_detail.xml @@ -0,0 +1,22 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_team_userinfo.xml b/app/src/main/res/layout/activity_browser.xml similarity index 39% rename from app/src/main/res/layout/fragment_team_userinfo.xml rename to app/src/main/res/layout/activity_browser.xml index 7176c2c520c7b30ab2cb5d57f0173048f73a4c4c..f86185f718984bb573e1750bdd6ebf0dd9059d14 100644 --- a/app/src/main/res/layout/fragment_team_userinfo.xml +++ b/app/src/main/res/layout/activity_browser.xml @@ -1,12 +1,13 @@ - + tools:context="net.oschina.app.improve.main.BrowserActivity"> - - - \ No newline at end of file + diff --git a/app/src/main/res/layout/activity_comments.xml b/app/src/main/res/layout/activity_comments.xml new file mode 100644 index 0000000000000000000000000000000000000000..26cfead46f1028671373f073f74c6489244abcb8 --- /dev/null +++ b/app/src/main/res/layout/activity_comments.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_crop.xml b/app/src/main/res/layout/activity_crop.xml new file mode 100644 index 0000000000000000000000000000000000000000..9b43c669335b1fc49a4649a6978017a5aa2ad8b2 --- /dev/null +++ b/app/src/main/res/layout/activity_crop.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_detail.xml b/app/src/main/res/layout/activity_detail.xml index a1198a58c5ade75dfe37590c92323af4bfb3cc2d..a98fea53aa51999a95ffd1e26929ce16092e7a34 100644 --- a/app/src/main/res/layout/activity_detail.xml +++ b/app/src/main/res/layout/activity_detail.xml @@ -1,6 +1,5 @@ diff --git a/app/src/main/res/layout/activity_detail_v2.xml b/app/src/main/res/layout/activity_detail_v2.xml new file mode 100644 index 0000000000000000000000000000000000000000..70d2cd376e10906a2f33752a5473b626bb2adec6 --- /dev/null +++ b/app/src/main/res/layout/activity_detail_v2.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_feed_back.xml b/app/src/main/res/layout/activity_feed_back.xml new file mode 100644 index 0000000000000000000000000000000000000000..ce1ac157ee41320e924dfe1079ce72031fee6903 --- /dev/null +++ b/app/src/main/res/layout/activity_feed_back.xml @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + +