Compare commits

...

99 Commits

Author SHA1 Message Date
28440d97de 删除无用代码 2019-04-08 18:00:21 +08:00
2b2b71fe01 资讯文章超链接支持跳转到社区文章 2019-04-04 16:21:50 +08:00
f5a9e7b487 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2019-04-03 17:56:56 +08:00
d43842a0e6 社区搜索新增页面增加关键字统计和点击跳转时增加到历史搜索 2019-04-03 17:56:42 +08:00
a557962f17 微调UI 2019-04-02 18:32:49 +08:00
560c682157 完成光环助手V3.6.3 RELEASE(20190402-1130)测试问题汇总(6,7,8) 2019-04-02 17:41:48 +08:00
a0ae36f511 修复问题编辑图片数量的显示错误问题 2019-04-02 15:57:21 +08:00
bdee17ffc4 修复社区选择排序问题 2019-04-02 09:59:12 +08:00
5829f09f8c 调整文案 2019-04-01 20:18:00 +08:00
bc6fa5e7db 更换编辑框图标 2019-04-01 18:07:06 +08:00
1607cea9ce Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2019-04-01 17:58:33 +08:00
426019ea7c 光环助手V3.6.3 RELEASE(20190331-1830)测试问题汇总(前端)(1.3.4.10) https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/483 2019-04-01 17:57:08 +08:00
1b878a50c4 调整关闭评论点击的 toast 文案 2019-04-01 17:13:43 +08:00
97525189b7 调整反馈文案 2019-04-01 16:59:38 +08:00
999947751a 修复回答浮窗在用户退出登录后也有可能显示的问题 2019-04-01 16:40:56 +08:00
2def61ab43 修复光环助手V3.6.3 RELEASE(20190331-1830)测试问题汇总(6,7,8,9) https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/483 2019-04-01 16:28:17 +08:00
5e07ef488c 整理重复定义的权限 2019-04-01 11:10:40 +08:00
7af47c0caf 调整资源位置 2019-04-01 11:10:12 +08:00
1a5ed3c05f 调整代码 2019-03-31 17:05:47 +08:00
9cc9b09861 光环助手V3.6.3 RELEASE(20190328-1930)测试问题汇总(前端)(5.6.7.8.13) https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/480 2019-03-31 15:21:12 +08:00
cef4432d97 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2019-03-31 14:17:02 +08:00
18be6acc34 光环助手V3.6.3 RELEASE(20190329-1930)测试问题汇总(前端)(1.2.3.8.9) https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/482 2019-03-31 14:16:27 +08:00
27d0dd40d0 修复了版主不能修改问题图片数量的问题 2019-03-30 17:13:33 +08:00
b05fa626f6 处理一些内存泄漏问题 2019-03-30 14:41:31 +08:00
f1fc84ea5f 修复答案被隐藏时的闪退问题 2019-03-30 14:40:55 +08:00
3942154c05 修复缺少路径引起的闪退问题 2019-03-30 14:23:52 +08:00
ff182ee3c7 修复了光环助手V3.6.3 RELEASE(20190328-1930)测试问题汇总的(1,2,9,10,11) https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/480 2019-03-30 10:38:01 +08:00
10cc275970 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/qa/AskFragment.kt
2019-03-29 17:03:41 +08:00
21821d584e 光环助手V3.6.3 DEV(20190328-1830)测试问题汇总(前端)(1.6.7.13.14.15) https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/479 2019-03-29 17:01:43 +08:00
6b8716eff8 补充社区搜索事件 MTA https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/478 2019-03-29 15:58:28 +08:00
47434e2943 处理了环助手V3.6.3 DEV(20190328-1830)测试问题汇总的(3,4,5,8,10,12) 2019-03-29 15:05:29 +08:00
4c3b327cff 完成数据统计需求 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/477 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/478 2019-03-29 11:00:37 +08:00
3454d13e48 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2019-03-28 20:55:58 +08:00
0aad7c59ee 源码引入matisse库 2019-03-28 20:55:49 +08:00
ee8e4e0338 修复社区文章无法置顶的问题 2019-03-28 18:29:50 +08:00
a430c51c97 让测试社区隐藏了也能点击进入 2019-03-28 18:20:53 +08:00
b59508e9e5 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2019-03-28 16:58:36 +08:00
08deac1dea 光环助手V3.6.3 DEV(20190327-1830)测试问题汇总(前端)(6.8.13.14.15) https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/476 2019-03-28 16:58:28 +08:00
a2dc3f3d5b 修复了部分 光环助手V3.6.3 DEV(20190327-1830)测试问题 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/476 2019-03-28 16:25:42 +08:00
679cfab088 社区搜索历史页面间距微调 2019-03-28 10:11:22 +08:00
9144595aaf 修复打包错误问题 2019-03-27 18:44:36 +08:00
8a545180a2 文章详情-评论详情UI微调 2019-03-27 17:37:56 +08:00
17c5793558 增加关闭评论确定弹窗 2019-03-27 16:15:05 +08:00
8afc346a2c 添加测试用的推送点击 toast 2019-03-27 15:49:35 +08:00
026bb7f67b 添加 CSS 和 JS 的外联依赖 2019-03-27 15:48:39 +08:00
b971e7dbf6 添加敏感词错误码 2019-03-27 15:48:00 +08:00
ec39ef16e4 优化社区搜索历史数据库操作 2019-03-27 11:14:51 +08:00
ae07bacbb7 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2019-03-27 10:41:44 +08:00
0f0d8da6cd merge 2019-03-27 10:41:37 +08:00
2a1c99efac 社区搜索热门增加置顶功能 2019-03-27 10:40:01 +08:00
caa89d3f4c 修复了回答详情列表较长上下滑动时会存在偏移的问题 2019-03-27 10:26:24 +08:00
1602816d08 调整回答详情上下滑动动画距离 2019-03-26 19:58:50 +08:00
1062cf5924 处理一些内存泄漏问题 2019-03-26 19:45:46 +08:00
f6e5cd3fd7 更新微信分享、登录SDK 2019-03-26 18:14:06 +08:00
c675196cb2 修复一些闪退问题 2019-03-26 16:35:21 +08:00
8b9c2668d1 完成3月第4周需求汇总 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/475 2019-03-26 15:54:43 +08:00
c1a927ed88 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2019-03-26 15:09:56 +08:00
4d4416c1df 社区搜索增加文章和用户模块 2019-03-26 15:09:46 +08:00
f4833983c0 完成3月第3周需求汇总 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/473 2019-03-26 11:24:05 +08:00
89eb99d813 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2019-03-25 18:28:00 +08:00
683a68d179 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/qa/answer/detail/AnswerDetailFragment.kt
#	app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java
2019-03-25 18:26:13 +08:00
598af67338 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/qa/answer/detail/AnswerDetailFragment.kt
#	app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java
2019-03-25 18:25:41 +08:00
d9d0ffc3b9 基本完成社区前端优化需求汇总 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/470 2019-03-25 18:16:18 +08:00
4d8e04580e 1.问答模块增加提问悬浮按钮
2.问答搜索增加默认搜索文案
3.问答搜索增加热门搜索区域
2019-03-25 18:15:17 +08:00
cfaddf2f22 基本完成社区版主权限强化需求 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/471 2019-03-25 16:45:42 +08:00
c72b194107 优化问答模块社区隐藏的交互 2019-03-25 14:27:09 +08:00
d7f33ff8b1 修复编译问题 2019-03-23 17:33:31 +08:00
91e491b66a 基本完成回答详情与社区文章详情优化 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/463 2019-03-23 17:26:16 +08:00
31b7e40ab0 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2019-03-22 18:58:53 +08:00
f2b094fff0 统一内容数值显示规则 完成 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/468 2019-03-22 18:54:55 +08:00
185ee7f0f4 调整选择游戏社区的排序,已安装相应游戏的放到最前 2019-03-22 18:25:14 +08:00
f446b15f7a Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2019-03-22 18:01:03 +08:00
52a833f18b 社区文章/回答 富文本编辑框统一插入样式 2019-03-22 18:00:51 +08:00
37fc68977c 根据接口调整回答详情的可拖动切换设定 2019-03-22 15:50:11 +08:00
96ee71a594 Merge remote-tracking branch 'origin/dev' into dev 2019-03-22 10:55:35 +08:00
1c2dda9353 基本完成提问与问题详情优化需求 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/464 2019-03-22 10:55:07 +08:00
96a9fd0ad7 富文本编辑框增加引用样式 2019-03-22 10:51:37 +08:00
c53c27e350 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2019-03-21 15:25:39 +08:00
fd4f32bb3c 回答编辑框增加各种内容样式 2019-03-21 15:25:31 +08:00
cbd2d8ed6c 修复图片上传闪退BUG 2019-03-20 18:32:11 +08:00
3dd06bc620 简单处理问题页面多张图片上传 2019-03-20 18:28:17 +08:00
3a829e1cfd 重构回答编辑 2019-03-20 15:40:48 +08:00
183e1a85c3 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2019-03-20 10:55:09 +08:00
6b696234ab 回答编辑支持批量插入图片 2019-03-20 10:54:58 +08:00
21ac1d1f17 基本完成答案详情上下滑动功能,待接口数据再调试 2019-03-20 10:23:33 +08:00
4163b81f70 Merge head 2019-03-19 18:10:34 +08:00
6c3268ce72 简单包裹答案详情页面以实现上下拖拽切换回答 2019-03-19 18:08:06 +08:00
4d87f86fcd Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2019-03-19 14:40:20 +08:00
4a37401dc2 RichEditor增加元件样式回调 2019-03-19 14:40:06 +08:00
8cf90193fc 修复一个数组越界造成的闪退问题 2019-03-18 16:12:27 +08:00
9942a51cad Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2019-03-11 18:24:47 +08:00
4980d96c8c 修复当后台返回错误的游戏标签时会闪退的问题 2019-03-11 18:24:37 +08:00
f32c8748ed Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2019-03-11 18:10:26 +08:00
7b886679e1 修改礼包图标大小 2019-03-11 18:08:52 +08:00
2620c04b09 捕抓闪退异常 (ObservableUtil 这个地方贡献了得有40%的闪退量) 2019-03-10 10:07:03 +08:00
c22157f2f5 修复了关注页面被销毁网络回调回来会导致闪退的问题 2019-03-08 09:44:54 +08:00
09f02bc225 修复插件化隐藏后无法一键修复问题 2019-03-07 15:57:38 +08:00
9fc9549a28 光环前端需求汇总(2019年3月第1周)(1.4.6.7.8)https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/461 2019-03-07 14:55:35 +08:00
0099afad09 update changelog 2019-03-04 10:00:08 +08:00
298 changed files with 12316 additions and 3363 deletions

View File

@ -35,4 +35,11 @@
### Ver 3.6.1
* 可以后台控制关闭资讯功能
* 版块、分类、专题详情、游戏详情、礼包详情增加预览骨架
* 下载按钮状态可以通过接口屏蔽相应的包
* 下载按钮状态可以通过接口屏蔽相应的包
### Ver 3.6.2
* 资讯/问答入口和插件功能线上控制(不可逆)
* 首页不显示已安装的游戏
* 插件求版本功能增加内部跳转
* 下载面板增加公告和版本说明功能
* 接入腾讯`广点通`(广告)

View File

@ -273,6 +273,7 @@ dependencies {
implementation 'com.ethanhua:skeleton:1.1.1'
implementation 'io.supercharge:shimmerlayout:2.1.0'
implementation "com.tencent.mm.opensdk:wechat-sdk-android-without-mta:5.3.1"
implementation project(':libraries:gid')
implementation project(':libraries:LGLibrary')
@ -280,9 +281,10 @@ dependencies {
implementation project(':libraries:QQShare')
implementation project(':libraries:TalkingData')
implementation project(':libraries:UmengPush')
implementation project(':libraries:WechatShare')
// implementation project(':libraries:WechatShare')
implementation project(':libraries:LogHub')
implementation project(':libraries:im')
implementation project(':libraries:Matisse')
}
File propFile = file('sign.properties')
if (propFile.exists()) {

View File

@ -41,12 +41,7 @@
<uses-permission android:name = "android.permission.WRITE_SETTINGS" />
<!-- bugly with tinker -->
<uses-permission android:name = "android.permission.READ_PHONE_STATE" />
<uses-permission android:name = "android.permission.INTERNET" />
<uses-permission android:name = "android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name = "android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name = "android.permission.READ_LOGS" />
<uses-permission android:name = "android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name = "android.permission.REQUEST_INSTALL_PACKAGES" />
<supports-screens
@ -398,6 +393,15 @@
</intent-filter >
</activity >
<activity
android:name="${applicationId}.wxapi.WXEntryActivity"
android:label="@string/app_name"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:exported="true"
android:launchMode="singleTop"
android:screenOrientation = "portrait" >
</activity>
<provider
android:name = "android.support.v4.content.FileProvider"
android:authorities = "${applicationId}"

View File

@ -4,12 +4,14 @@
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" type="text/css" href="normalize.css">
<link rel="stylesheet" type="text/css" href="style.css">
<link rel="stylesheet" type="text/css" href="https://resource.ghzs.com/css/halo_app.css">
</head>
<body>
<div id="editor" contenteditable="true"></div>
<script type="text/javascript" src="zepto.min.js"></script>
<script type="text/javascript" src="rich_editor.js"></script>
<script type="text/javascript" src="content.js"></script>
<script type="text/javascript" src="https://resource.ghzs.com/js/halo_app.js"></script>
<!--<script src="https://cdnjs.cloudflare.com/ajax/libs/vanilla-lazyload/10.15.0/lazyload.min.js"></script>-->
</body>
</html>

View File

@ -14,6 +14,17 @@
* limitations under the License.
*/
// alert("")
// link block
// var html = "<div style = \"background:#f5f5f5;padding:10px;\", contenteditable=\"false\", spellcheck=\"false\" >\n" +
// "<font style = \"display: inline-block;white-space: nowrap;max-width: 100%;overflow: hidden; text-overflow:ellipsis;\" size = \"4\" >In HTML and XHTML, the blockquote element defines</font>\n" +
// "<br>\n" +
// "<font style = \"display: inline-block;white-space: nowrap;max-width: 100%;overflow: hidden; text-overflow:ellipsis;\", size = \"3\" >In HTML and XHTML, the blockquote element defines</font>\n" +
// "</div>" +
// "<br>\n"
// document.execCommand('insertHTML', false, html);
var RE = {};
RE.currentSelection = {
@ -94,16 +105,8 @@ RE.setInputEnabled = function(inputEnabled) {
RE.editor.contentEditable = String(inputEnabled);
}
RE.setFocusByEnd = function() {
//alert("111111")
// var txt =RE.editor.createTextRange();
// ("22222")
// txt.moveStart('character',-1);
// ("333333")
// txt.collapse(true);
// ("444444")
// txt.select();
// alert("ddddddd")
RE.formatBlock = function() {
document.execCommand('formatBlock', false, 'p');
}
RE.undo = function() {
@ -166,6 +169,7 @@ RE.setFontSize = function(fontSize){
RE.setHeading = function(heading) {
document.execCommand('formatBlock', false, '<h'+heading+'>');
RE.sendElementNameToNative()
}
RE.setIndent = function() {
@ -190,6 +194,9 @@ RE.setJustifyRight = function() {
RE.setBlockquote = function() {
document.execCommand('formatBlock', false, '<blockquote>');
// var blockId = window.getSelection().focusNode.parentNode;
// $(blockId).addClass("haloBlock")
RE.sendElementNameToNative()
}
RE.insertImage = function(url) {
@ -197,12 +204,6 @@ RE.insertImage = function(url) {
RE.insertHTML(html);
}
//RE.lazyLoad = function() {
// var myLazyLoad = new LazyLoad({
// elements_selector: ".lazy"
// })
//}
// 替换成缩略图
RE.replaceTbImage = function(imgRuleFlag, gifRuleFlag) {
var imgs = document.getElementsByTagName("img");
@ -439,5 +440,34 @@ RE.editor.addEventListener("keyup", function(e) {
if (e.which == KEY_LEFT || e.which == KEY_RIGHT) {
RE.enabledEditingItems(e);
}
RE.sendElementNameToNative()
});
RE.editor.addEventListener("click", RE.enabledEditingItems);
RE.editor.addEventListener("click", function(e) {
RE.enabledEditingItems
RE.sendElementNameToNative()
});
// 返回组件标签 多个标签以"空格"划分
RE.sendElementNameToNative = function() {
if (window.getSelection) {
var selection = window.getSelection()
if (selection.rangeCount > 0) {
var range = selection.getRangeAt(0);
var container = range.startContainer;
var elements = " " + container.localName + " ";
var parentElement;
while(true) {
if(parentElement != null) {
parentElement = parentElement.parentElement
} else {
parentElement = container.parentElement
}
if (parentElement == null || parentElement.localName == null) {
break;
}
elements = elements + " " + parentElement.localName + " "
}
window.OnCursorChangeListener.onElements(elements);
}
}
}

View File

@ -0,0 +1,181 @@
package com.gh.base
import android.annotation.SuppressLint
import android.content.ClipboardManager
import android.content.Context
import android.os.Bundle
import android.text.TextUtils
import android.view.View
import android.webkit.JavascriptInterface
import butterknife.OnClick
import com.gh.common.view.RichEditor
import com.gh.gamecenter.R
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import com.lightgame.view.CheckableImageView
import kotterknife.bindView
abstract class BaseRichEditorActivity : BaseActivity() {
val mRichEditor by bindView<RichEditor>(R.id.rich_editor)
private val mEditorFont by bindView<CheckableImageView>(R.id.editor_font)
private val mEditorLink by bindView<CheckableImageView>(R.id.editor_link)
private val mEditorParagraph by bindView<CheckableImageView>(R.id.editor_paragraph)
private val mEditorFontBold by bindView<CheckableImageView>(R.id.editor_font_bold)
private val mEditorFontItalic by bindView<CheckableImageView>(R.id.editor_font_italic)
private val mEditorFontStrikeThrough by bindView<CheckableImageView>(R.id.editor_font_strikethrough)
private val mEditorParagraphH1 by bindView<CheckableImageView>(R.id.editor_paragraph_h1)
private val mEditorParagraphH2 by bindView<CheckableImageView>(R.id.editor_paragraph_h2)
private val mEditorParagraphH3 by bindView<CheckableImageView>(R.id.editor_paragraph_h3)
private val mEditorParagraphH4 by bindView<CheckableImageView>(R.id.editor_paragraph_h4)
private val mEditorParagraphQuote by bindView<CheckableImageView>(R.id.editor_paragraph_quote)
private val mEditorFontContainer by bindView<View>(R.id.editor_font_container)
private val mEditorParagraphContainer by bindView<View>(R.id.editor_paragraph_container)
private val mEditorLinkContainer by bindView<View>(R.id.editor_link_container)
private val mEditorInsertDetail by bindView<View>(R.id.editor_insert_detail)
@SuppressLint("AddJavascriptInterface")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 防止个别手机在Js里无法获取粘贴内容
mRichEditor.addJavascriptInterface(OnPasteListener(), "onPasteListener")
mRichEditor.addJavascriptInterface(OnCursorChangeListener(), "OnCursorChangeListener")
}
@OnClick(R.id.editor_image, R.id.editor_font, R.id.editor_link, R.id.editor_paragraph,
R.id.editor_font_bold, R.id.editor_font_italic, R.id.editor_font_strikethrough,
R.id.editor_paragraph_h1, R.id.editor_paragraph_h2, R.id.editor_paragraph_h3,
R.id.editor_paragraph_h4, R.id.editor_font_container, R.id.editor_paragraph_container,
R.id.editor_paragraph_quote)
fun onRichClick(view: View) {
when (view.id) {
R.id.editor_font -> {
mEditorFont.isChecked = !mEditorFont.isChecked
mEditorParagraph.isChecked = false
mEditorLink.isChecked = false
mEditorFontContainer.visibility = if (mEditorFont.isChecked) View.VISIBLE else View.GONE
mEditorParagraphContainer.visibility = if (!mEditorFont.isChecked) View.VISIBLE else View.GONE
mEditorLinkContainer.visibility = if (!mEditorFont.isChecked) View.VISIBLE else View.GONE
mEditorInsertDetail.visibility = mEditorFontContainer.visibility
}
R.id.editor_paragraph -> {
mEditorParagraph.isChecked = !mEditorParagraph.isChecked
mEditorFont.isChecked = false
mEditorLink.isChecked = false
mEditorParagraphContainer.visibility = if (mEditorParagraph.isChecked) View.VISIBLE else View.GONE
mEditorFontContainer.visibility = if (!mEditorParagraph.isChecked) View.VISIBLE else View.GONE
mEditorLinkContainer.visibility = if (!mEditorParagraph.isChecked) View.VISIBLE else View.GONE
mEditorInsertDetail.visibility = mEditorParagraphContainer.visibility
}
R.id.editor_link -> {
mEditorLink.isChecked = !mEditorLink.isChecked
mEditorFont.isChecked = false
mEditorParagraph.isChecked = false
mEditorLinkContainer.visibility = if (mEditorLink.isChecked) View.VISIBLE else View.GONE
mEditorParagraphContainer.visibility = if (!mEditorLink.isChecked) View.VISIBLE else View.GONE
mEditorFontContainer.visibility = if (!mEditorLink.isChecked) View.VISIBLE else View.GONE
mEditorInsertDetail.visibility = mEditorLinkContainer.visibility
}
R.id.editor_font_bold -> {
mEditorFontBold.isChecked = !mEditorFontBold.isChecked
mRichEditor.setBold()
}
R.id.editor_font_italic -> {
mEditorFontItalic.isChecked = !mEditorFontItalic.isChecked
mRichEditor.setItalic()
}
R.id.editor_font_strikethrough -> {
mEditorFontStrikeThrough.isChecked = !mEditorFontStrikeThrough.isChecked
mRichEditor.setStrikeThrough()
}
R.id.editor_paragraph_h1 -> {
if (mEditorParagraphH1.isChecked) {
mRichEditor.formatBlock()
} else {
mRichEditor.setHeading(1)
}
mEditorParagraphH1.isChecked = !mEditorParagraphH1.isChecked
}
R.id.editor_paragraph_h2 -> {
if (mEditorParagraphH2.isChecked) {
mRichEditor.formatBlock()
} else {
mRichEditor.setHeading(2)
}
mEditorParagraphH2.isChecked = !mEditorParagraphH2.isChecked
}
R.id.editor_paragraph_h3 -> {
if (mEditorParagraphH3.isChecked) {
mRichEditor.formatBlock()
} else {
mRichEditor.setHeading(3)
}
mEditorParagraphH3.isChecked = !mEditorParagraphH3.isChecked
}
R.id.editor_paragraph_h4 -> {
if (mEditorParagraphH4.isChecked) {
mRichEditor.formatBlock()
} else {
mRichEditor.setHeading(4)
}
mEditorParagraphH4.isChecked = !mEditorParagraphH4.isChecked
}
R.id.editor_paragraph_quote -> {
if (mEditorParagraphQuote.isChecked) {
mRichEditor.formatBlock()
} else {
mRichEditor.setBlockquote()
}
mEditorParagraphQuote.isChecked = !mEditorParagraphQuote.isChecked
}
}
}
private inner class OnCursorChangeListener {
@JavascriptInterface
fun onElements(elements: String) {
Utils.log("-----------------------")
Utils.log(elements)
Utils.log(mRichEditor.html)
Utils.log("-----------------------")
mBaseHandler.post {
mEditorFontBold.isChecked = elements.contains(ELEMENT_NAME_BOLD)
mEditorFontItalic.isChecked = elements.contains(ELEMENT_NAME_ITALIC)
mEditorFontStrikeThrough.isChecked = elements.contains(ELEMENT_NAME_STRIKE)
mEditorParagraphH1.isChecked = elements.contains(ELEMENT_PARAGRAPH_H1)
mEditorParagraphH2.isChecked = elements.contains(ELEMENT_PARAGRAPH_H2)
mEditorParagraphH3.isChecked = elements.contains(ELEMENT_PARAGRAPH_H3)
mEditorParagraphH4.isChecked = elements.contains(ELEMENT_PARAGRAPH_H4)
mEditorParagraphQuote.isChecked = elements.contains(ELEMENT_PARAGRAPH_QUOTE)
}
}
}
private inner class OnPasteListener {
@JavascriptInterface
fun onPaste() {
val clipboard =
HaloApp.getInstance().application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clipText = clipboard.text.toString()
if (!TextUtils.isEmpty(clipText)) {
// 替换换行符号否则 插入失败
val text = clipText.replace("[ ]".toRegex(), "&nbsp;").replace("[\r\n]".toRegex(), "<br/>")
mBaseHandler.post { mRichEditor.insertHtml(text) }
}
}
}
companion object {
const val ELEMENT_NAME_BOLD = " b "
const val ELEMENT_NAME_ITALIC = " i "
const val ELEMENT_NAME_STRIKE = " strike "
const val ELEMENT_PARAGRAPH_H1 = " h1 "
const val ELEMENT_PARAGRAPH_H2 = " h2 "
const val ELEMENT_PARAGRAPH_H3 = " h3 "
const val ELEMENT_PARAGRAPH_H4 = " h4 "
const val ELEMENT_PARAGRAPH_QUOTE = " blockquote "
}
}

View File

@ -137,7 +137,8 @@ class GHUmengNotificationService : UmengMessageService() {
notificationManager.notify(getNotificationTag(context), NOTIFICATION_ID, notification)
} else {
if (HALO_MESSAGE_DIALOG == pushData.body?.custom) {
if (UserManager.getInstance().isLoggedIn
&& HALO_MESSAGE_DIALOG == pushData.body?.custom) {
// 回答了问题或者关注了问题的消息
val msg = gson.fromJson(message, PushMessageEntity::class.java)
val data = msg?.extra?.data
@ -164,8 +165,7 @@ class GHUmengNotificationService : UmengMessageService() {
bundle.putString(EntranceUtils.KEY_TO, AnswerDetailActivity::class.java.name)
EntranceUtils.jumpActivity(context, bundle)
DataUtils.onMtaEvent(context, "消息弹窗",
type, "Does not contains any parameter.")
DataUtils.onMtaEvent(context, "消息弹窗", type, "Does not contains any parameter.")
// 标记已读
val jsonObject = JSONObject()

View File

@ -102,6 +102,10 @@ class TimeElapsedHelper(val fragment: Fragment?, val activity: Activity?) {
}
}
fun resetCounting() {
elapsedTime = 0
}
fun pauseCounting() {
isWorking = false
}

View File

@ -106,6 +106,10 @@ public class Config {
public static boolean isShowPlugin(String gameId) {
SharedPreferences preferences = getPreferences();
boolean isFixPlugin = preferences.getBoolean(FIX_PLUGIN_KEY, false);
if (isFixPlugin) return true;
if (TextUtils.isEmpty(gameId) || !isExistDownloadFilter())
return false;
@ -118,10 +122,6 @@ public class Config {
}
}
SharedPreferences preferences = getPreferences();
boolean isFixPlugin = preferences.getBoolean(FIX_PLUGIN_KEY, false);
if (isFixPlugin) return true;
if ("all".equals(entity.getGame())) {
if (entity.getPluginfy() && filterTime(entity.getTime())) {
preferences.edit().putBoolean(FIX_PLUGIN_KEY, true).apply();
@ -134,6 +134,10 @@ public class Config {
}
public static boolean isShowPlugin() {
SharedPreferences preferences = getPreferences();
boolean isFixPlugin = preferences.getBoolean(FIX_PLUGIN_KEY, false);
if (isFixPlugin) return true;
if (!isExistDownloadFilter())
return false;

View File

@ -18,6 +18,7 @@ package com.gh.common.util
import android.animation.Animator
import android.support.annotation.RequiresApi
import android.view.ViewPropertyAnimator
/**
* Since [Android KTX] has not release a stable build yet,
@ -125,4 +126,26 @@ fun Animator.addPauseListener(
}
addPauseListener(listener)
return listener
}
fun ViewPropertyAnimator.doOnEnd(onEnd: ((animator: Animator?) -> Unit)? = null): ViewPropertyAnimator {
val listener = object : Animator.AnimatorListener {
override fun onAnimationRepeat(animation: Animator?) {
}
override fun onAnimationEnd(animation: Animator?) {
onEnd?.invoke(animation)
}
override fun onAnimationCancel(animation: Animator?) {
}
override fun onAnimationStart(animation: Animator?) {
}
}
this.setListener(listener)
return this
}

View File

@ -21,78 +21,41 @@ import retrofit2.HttpException
object CommentHelper {
// TODO 合并这两个方法的共同部分
@JvmStatic
fun showCommunityArticleCommentOptions(
context: Context,
commentEntity: CommentEntity,
showConversation: Boolean,
articleId: String,
communityId: String,
listener: OnCommentCallBackListener?) {
val dialogOptions = ArrayList<String>()
if (commentEntity.me == null || !commentEntity.me?.isAnswerCommented!!) {
dialogOptions.add("回复")
}
dialogOptions.add("复制")
dialogOptions.add("举报")
if (commentEntity.parentUser != null && showConversation) {
dialogOptions.add("查看对话")
}
DialogUtils.showListDialog(context, dialogOptions, null) {
when (it) {
"回复" -> {
context.ifLogin("社区文章详情-评论-回复") {
if (listener != null) {
listener.onCommentCallback(commentEntity)
} else if (!TextUtils.isEmpty(commentEntity.id)) {
context.startActivity(MessageDetailActivity.getMessageDetailIntent(context, commentEntity, commentEntity.id))
} else {
Utils.toast(context, "缺少关键属性")
}
}
}
"复制" -> copyText(commentEntity.content, context)
"举报" -> context.ifLogin("社区文章详情-评论-举报") {
showReportTypeDialog(context) { reportType ->
PostCommentUtils.reportCommunityArticleComment(context, communityId, articleId, commentEntity.id, reportType,
object : PostCommentUtils.PostCommentListener {
override fun postSuccess(response: JSONObject?) {
Utils.toast(context, "感谢您的举报")
}
override fun postFailed(error: Throwable?) {
if (error == null) {
Utils.toast(context, "举报失败,请稍后重试")
} else {
Utils.toast(context, "举报失败,${error.message}")
}
}
})
}
}
"查看对话" -> {
context.startActivity(CommentDetailActivity
.getCommunityArticleCommentIntent(context, articleId, commentEntity.id, communityId, null))
}
}
}
fun showCommunityArticleCommentOptions(context: Context,
commentEntity: CommentEntity,
showConversation: Boolean,
articleId: String,
communityId: String,
listener: OnCommentCallBackListener?) {
showCommentOptions(context = context,
commentEntity = commentEntity,
showConversation = showConversation,
articleId = articleId,
communityId = communityId,
listener = listener)
}
@JvmStatic
fun showAnswerCommentOptions(
context: Context,
commentEntity: CommentEntity,
showConversation: Boolean,
answerId: String,
listener: OnCommentCallBackListener?) {
fun showAnswerCommentOptions(context: Context,
commentEntity: CommentEntity,
showConversation: Boolean,
answerId: String,
listener: OnCommentCallBackListener?) {
showCommentOptions(context = context,
commentEntity = commentEntity,
showConversation = showConversation,
answerId = answerId,
listener = listener)
}
private fun showCommentOptions(context: Context,
commentEntity: CommentEntity,
showConversation: Boolean,
articleId: String? = null,
communityId: String? = null,
answerId: String? = null,
listener: OnCommentCallBackListener? = null) {
val dialogOptions = ArrayList<String>()
if (commentEntity.me == null || !commentEntity.me?.isAnswerCommented!!) {
@ -103,9 +66,10 @@ object CommentHelper {
dialogOptions.add("举报")
commentEntity.me?.let {
if (it.isModerator && (
it.moderatorPermissions.contains(MeEntity.HIDE_ANSWER_COMMENT)
|| it.moderatorPermissions.contains(MeEntity.TOP_ANSWER_COMMENT))) {
if (it.isModerator || (it.moderatorPermissions.contains(MeEntity.HIDE_ANSWER_COMMENT)
|| it.moderatorPermissions.contains(MeEntity.TOP_ANSWER_COMMENT)
|| it.moderatorPermissions.contains(MeEntity.HIDE_COMMUNITY_ARTICLE)
|| it.moderatorPermissions.contains(MeEntity.TOP_COMMUNITY_ARTICLE_COMMENT))) {
dialogOptions.add("管理")
}
}
@ -116,7 +80,7 @@ object CommentHelper {
DialogUtils.showListDialog(context, dialogOptions, null) {
when (it) {
"管理" -> showControlDialog(context, answerId, commentEntity, commentEntity.me!!)
"管理" -> showControlDialog(context, answerId, articleId, communityId, commentEntity, commentEntity.me!!)
"回复" -> {
context.ifLogin("回答详情-评论-回复") {
@ -132,43 +96,63 @@ object CommentHelper {
"复制" -> copyText(commentEntity.content, context)
"举报" -> context.ifLogin("回答详情-评论-举报") {
showReportTypeDialog(context) { reportType ->
PostCommentUtils.postAnswerReportData(context, commentEntity.id, answerId, reportType,
object : PostCommentUtils.PostCommentListener {
override fun postSuccess(response: JSONObject?) {
Utils.toast(context, "感谢您的举报")
}
"举报" -> {
context.ifLogin("回答详情-评论-举报") {
showReportTypeDialog(context) { reportType ->
override fun postFailed(error: Throwable?) {
if (error == null) {
Utils.toast(context, "举报失败,请稍后重试")
} else {
Utils.toast(context, "举报失败,${error.message}")
}
val commentListener = object : PostCommentUtils.PostCommentListener {
override fun postSuccess(response: JSONObject?) {
Utils.toast(context, "感谢您的举报")
}
override fun postFailed(error: Throwable?) {
if (error == null) {
Utils.toast(context, "举报失败,请稍后重试")
} else {
Utils.toast(context, "举报失败,${error.message}")
}
})
}
}
if (answerId != null) {
PostCommentUtils.postAnswerReportData(context, commentEntity.id, answerId, reportType, commentListener)
} else {
PostCommentUtils.reportCommunityArticleComment(context, communityId, articleId, commentEntity.id, reportType, commentListener)
}
}
}
}
"查看对话" -> {
context.startActivity(CommentDetailActivity
.getAnswerCommentIntent(context, commentEntity.id, answerId, null))
if (answerId != null) {
context.startActivity(CommentDetailActivity
.getAnswerCommentIntent(context, commentEntity.id, answerId, null))
} else {
context.startActivity(CommentDetailActivity
.getCommunityArticleCommentIntent(context, articleId, commentEntity.id, communityId, null))
}
}
}
}
}
private fun showControlDialog(context: Context, answerId: String, comment: CommentEntity, me: MeEntity) {
private fun showControlDialog(context: Context,
answerId: String? = null,
articleId: String? = null,
communityId: String? = null,
comment: CommentEntity,
me: MeEntity) {
val dialogOptions = arrayListOf<String>()
val highlight = "置顶评论"
val hide = "隐藏评论"
if (me.moderatorPermissions.contains(MeEntity.TOP_ANSWER_COMMENT)) {
if (me.moderatorPermissions.contains(MeEntity.TOP_ANSWER_COMMENT)
|| me.moderatorPermissions.contains(MeEntity.TOP_COMMUNITY_ARTICLE_COMMENT)) {
dialogOptions.add(highlight)
}
if (me.moderatorPermissions.contains(MeEntity.HIDE_ANSWER_COMMENT)) {
if (me.moderatorPermissions.contains(MeEntity.HIDE_ANSWER_COMMENT)
|| me.moderatorPermissions.contains(MeEntity.HIDE_COMMUNITY_ARTICLE_COMMENT)) {
dialogOptions.add(hide)
}
@ -179,9 +163,11 @@ object CommentHelper {
}
val disabledOptions = arrayListOf<String>()
if (comment.priority != 0) {
disabledOptions.add(highlight)
}
comment.me?.let {
if (it.isAnswerCommented) {
disabledOptions.add(highlight)
@ -191,7 +177,6 @@ object CommentHelper {
DialogUtils.showListDialog(context, dialogOptions, disabledOptions) {
when (it) {
highlight -> {
if (comment.priority != 0) {
Utils.toast(context, "评论已经置顶")
return@showListDialog
@ -204,77 +189,101 @@ object CommentHelper {
}
}
DialogUtils.showAlertDialog(context, highlight, content,
"确定", "取消",
{
RetrofitManager.getInstance(context).api
.highlightAnswerComment(answerId, comment.id)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
if (me.moderatorLevel == MeEntity.MODERATOR_LEVEL_PRIMARY) {
Utils.toast(context, "提交成功")
} else {
Utils.toast(context, "置顶成功,请刷新列表")
}
}
val highlightObserver = object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
if (me.moderatorLevel == MeEntity.MODERATOR_LEVEL_PRIMARY) {
Utils.toast(context, "提交成功")
} else {
Utils.toast(context, "置顶成功,请刷新列表")
}
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
e?.let { httpException ->
if (httpException.code() == 403) {
val string = e.response().errorBody()?.string()
val errorJson = JSONObject(string)
val errorCode = errorJson.getInt("code")
if (errorCode == 403059) {
Utils.toast(getApplication(), "权限错误,请刷新后重试")
return
} else {
Utils.toast(getApplication(), e.message())
}
}
}
}
})
}, null)
override fun onFailure(e: HttpException?) {
super.onFailure(e)
e?.let { httpException ->
if (httpException.code() == 403) {
val string = e.response().errorBody()?.string()
val errorJson = JSONObject(string)
val errorCode = errorJson.getInt("code")
if (errorCode == 403059) {
Utils.toast(getApplication(), "权限错误,请刷新后重试")
return
} else {
Utils.toast(getApplication(), e.message())
}
}
}
}
}
if (answerId != null) {
DialogUtils.showAlertDialog(context, highlight, content,
"确定", "取消", {
RetrofitManager.getInstance(context).api
.highlightAnswerComment(answerId, comment.id)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(highlightObserver)
}, null)
} else {
DialogUtils.showAlertDialog(context, highlight, content,
"确定", "取消", {
RetrofitManager.getInstance(context).api
.highlightCommunityArticleComment(communityId, articleId, comment.id)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(highlightObserver)
}, null)
}
}
hide -> {
DialogUtils.showAlertDialog(context, hide, content,
"确定", "取消",
{
RetrofitManager.getInstance(context).api
.hideAnswerComment(answerId, comment.id)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
if (me.moderatorLevel == MeEntity.MODERATOR_LEVEL_PRIMARY) {
Utils.toast(context, "提交成功")
} else {
Utils.toast(context, "隐藏成功,请刷新列表")
}
}
val hideObserver = object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
if (me.moderatorLevel == MeEntity.MODERATOR_LEVEL_PRIMARY) {
Utils.toast(context, "提交成功")
} else {
Utils.toast(context, "隐藏成功,请刷新列表")
}
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
e?.let { httpException ->
if (httpException.code() == 403) {
val string = e.response().errorBody()?.string()
val errorJson = JSONObject(string)
val errorCode = errorJson.getInt("code")
if (errorCode == 403059) {
Utils.toast(getApplication(), "权限错误,请刷新后重试")
return
} else {
Utils.toast(getApplication(), e.message())
}
}
}
}
})
}, null)
override fun onFailure(e: HttpException?) {
super.onFailure(e)
e?.let { httpException ->
if (httpException.code() == 403) {
val string = e.response().errorBody()?.string()
val errorJson = JSONObject(string)
val errorCode = errorJson.getInt("code")
if (errorCode == 403059) {
Utils.toast(getApplication(), "权限错误,请刷新后重试")
return
} else {
Utils.toast(getApplication(), e.message())
}
}
}
}
}
if (answerId != null) {
DialogUtils.showAlertDialog(context, hide, content,
"确定", "取消", {
RetrofitManager.getInstance(context).api
.hideAnswerComment(answerId, comment.id)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(hideObserver)
}, null)
} else {
DialogUtils.showAlertDialog(context, hide, content,
"确定", "取消", {
RetrofitManager.getInstance(context).api
.hideCommunityArticleComment(communityId, articleId, comment.id)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(hideObserver)
}, null)
}
}
}
}

View File

@ -458,7 +458,7 @@ public class CommentUtils {
commentEntity.setVote(commentEntity.getVote() + 1);
commentLikeCountTv.setTextColor(ContextCompat.getColor(context, R.color.theme));
commentLikeIv.setImageResource(R.drawable.vote_icon_select);
commentLikeCountTv.setText(String.valueOf(commentEntity.getVote()));
commentLikeCountTv.setText(NumberUtils.transSimpleCount(commentEntity.getVote()));
commentLikeCountTv.setVisibility(View.VISIBLE);
PostCommentUtils.addCommentVote(context, commentEntity.getId(),
@ -476,7 +476,7 @@ public class CommentUtils {
commentEntity.setVote(commentEntity.getVote() - 1);
commentLikeCountTv.setTextColor(ContextCompat.getColor(context, R.color.hint));
commentLikeIv.setImageResource(R.drawable.vote_icon_unselect);
commentLikeCountTv.setText(String.valueOf(commentEntity.getVote()));
commentLikeCountTv.setText(NumberUtils.transSimpleCount(commentEntity.getVote()));
if (commentEntity.getVote() == 0) {
commentLikeCountTv.setVisibility(View.GONE);
} else {
@ -518,7 +518,7 @@ public class CommentUtils {
commentEntity.setVote(commentEntity.getVote() + 1);
commentLikeCountTv.setTextColor(ContextCompat.getColor(context, R.color.theme));
commentLikeIv.setImageResource(R.drawable.vote_icon_select);
commentLikeCountTv.setText(String.valueOf(commentEntity.getVote()));
commentLikeCountTv.setText(NumberUtils.transSimpleCount(commentEntity.getVote()));
commentLikeCountTv.setVisibility(View.VISIBLE);
PostCommentUtils.voteAnswerComment(context, answerId, articleId, articleCommunityId, commentEntity.getId(),
@ -536,7 +536,7 @@ public class CommentUtils {
commentEntity.setVote(commentEntity.getVote() - 1);
commentLikeCountTv.setTextColor(ContextCompat.getColor(context, R.color.hint));
commentLikeIv.setImageResource(R.drawable.vote_icon_unselect);
commentLikeCountTv.setText(String.valueOf(commentEntity.getVote()));
commentLikeCountTv.setText(NumberUtils.transSimpleCount(commentEntity.getVote()));
if (commentEntity.getVote() == 0) {
commentLikeCountTv.setVisibility(View.GONE);
} else {

View File

@ -1,45 +0,0 @@
package com.gh.common.util
import com.gh.gamecenter.qa.entity.AskGameSelectEntity
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.schedulers.Schedulers
/**
* 用于判断社区跳转前社区是否可用
*/
object CommunityHelper {
private var availableCommunityList = listOf<AskGameSelectEntity>()
@JvmStatic
fun getAvailableCommunityList() {
RetrofitManager.getInstance(HaloApp.getInstance().application).api
.getAskGameSelect(HaloApp.getInstance().channel
, UrlFilterUtils.getFilterQuery("status", "opened"), 1, 100)
.subscribeOn(Schedulers.io())
.subscribe(object : Response<List<AskGameSelectEntity>>() {
override fun onResponse(response: List<AskGameSelectEntity>?) {
if (response != null && response.isNotEmpty()) {
availableCommunityList = response
}
}
})
}
@JvmStatic
fun isCommunityAvailable(communityId: String?): Boolean {
communityId?.let {
if (availableCommunityList.isEmpty()) return true
for (entity in availableCommunityList) {
if (communityId == entity.id) {
return true
}
}
}
return false
}
}

View File

@ -1,5 +1,6 @@
package com.gh.common.util;
import android.app.ActivityManager;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
@ -238,7 +239,6 @@ public class DeviceUtils {
return "";
}
// ping domain
public static String ping(String domain) {
try {
@ -257,5 +257,13 @@ public class DeviceUtils {
}
}
public static long getTotalRamSizeOfDevice(Context context) {
ActivityManager actManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo();
if (actManager != null) {
actManager.getMemoryInfo(memInfo);
}
return memInfo.totalMem / (1024 * 1024);
}
}

View File

@ -86,7 +86,7 @@ object DirectUtils {
"community_article" -> context.startActivity(ArticleDetailActivity.getIntent(context, linkEntity.community!!, linkEntity.link!!, entrance, path))
"community_column" -> context.startActivity(CommunitySubjectActivity.getIntent(context, linkEntity.community!!, linkEntity.link, entrance))
"community_column" -> context.startActivity(CommunitySubjectActivity.getIntent(context, linkEntity.community!!, linkEntity.link, entrance, path))
"community_special_column" -> context.startActivity(AskColumnDetailActivity.getIntentByColumnId(context, linkEntity.link, linkEntity.community!!, entrance, path))

View File

@ -88,14 +88,14 @@ inline fun <reified T : Any> T.toJson(): String {
}
/**
* 快速点击两下
* 在限定 interval 里只触发一次 action
*/
fun fastDoubleClickAction(id: Int, interval: Long = 300, action: (() -> Unit)? = null) {
if (ClickUtils.isFastDoubleClick(id, interval)) {
fun debounceActionWithInterval(id: Int, interval: Long = 300, action: (() -> Unit)? = null) {
if (!ClickUtils.isFastDoubleClick(id, interval)) {
action?.invoke()
}
}
fun View.fastDoubleClickAction(interval: Long, action: (() -> Unit)? = null) {
fastDoubleClickAction(id, interval, action)
fun View.debounceActionWithInterval(interval: Long = 300, action: (() -> Unit)? = null) {
debounceActionWithInterval(this.id, interval, action)
}

View File

@ -15,7 +15,6 @@ object GameRepositoryHelper {
private const val KEY_GAME_REPOSITORY = "game_repository"
// TODO 会有多线程操作问题(在此列表获取补充游戏数据时进行下拉刷新修改此列表)
var gameCollectionList: List<SubjectEntity> = arrayListOf()
init {
@ -28,22 +27,6 @@ object GameRepositoryHelper {
@JvmStatic
fun getGameRepository(context: Context) {
// Test only
// RetrofitManager.getInstance(context)
// .api
// .remenkapai
// .subscribeOn(Schedulers.io())
// .subscribe(object : Response<List<GameEntity>>() {
// override fun onResponse(response: List<GameEntity>?) {
// val subjectEntityList = arrayListOf<SubjectEntity>()
// val subjectEntity = SubjectEntity(id = "5ac46cca2924bc2870438d28")
// subjectEntity.data = ArrayList(response)
// subjectEntityList.add(subjectEntity)
// updateGameRepository(subjectEntityList)
// }
// })
RetrofitManager.getInstance(context)
.api
.reserveColumns
@ -86,13 +69,12 @@ object GameRepositoryHelper {
fun getOneUniqueGame(collectionId: String?, gameIdList: List<String>): GameEntity? {
collectionId?.let {
val collection = gameCollectionList.find { it.id == collectionId }
// Test only
// val collection = gameCollectionList.find { it.id == "5ac46cca2924bc2870438d28" }
collection?.let {
val game = collection.data?.find { game -> findUniqueGame(game, gameIdList) }
game?.let {
collection.data?.remove(game)
// 产品说要记录补充专题的曝光数,所以这个游戏附带了所在专题的名字
game.subjectName = collection.name
return game
}
}

View File

@ -16,9 +16,9 @@ import com.sina.weibo.sdk.auth.Oauth2AccessToken;
import com.sina.weibo.sdk.auth.WbAuthListener;
import com.sina.weibo.sdk.auth.WbConnectErrorMessage;
import com.sina.weibo.sdk.auth.sso.SsoHandler;
import com.tencent.mm.sdk.openapi.IWXAPI;
import com.tencent.mm.sdk.openapi.SendAuth;
import com.tencent.mm.sdk.openapi.WXAPIFactory;
import com.tencent.mm.opensdk.modelmsg.SendAuth;
import com.tencent.mm.opensdk.openapi.IWXAPI;
import com.tencent.mm.opensdk.openapi.WXAPIFactory;
import com.tencent.tauth.IUiListener;
import com.tencent.tauth.Tencent;
import com.tencent.tauth.UiError;

View File

@ -2,9 +2,11 @@ package com.gh.common.util
import android.content.Context
import android.content.res.Resources
import android.graphics.Bitmap
import android.graphics.drawable.Animatable
import android.graphics.drawable.ColorDrawable
import android.net.Uri
import android.os.Build
import android.support.annotation.DrawableRes
import android.support.v4.content.ContextCompat
import com.facebook.common.executors.CallerThreadExecutor
@ -20,6 +22,7 @@ import com.facebook.imagepipeline.request.ImageRequest
import com.facebook.imagepipeline.request.ImageRequestBuilder
import com.gh.common.constant.Config
import com.gh.gamecenter.R
import java.io.ByteArrayOutputStream
object ImageUtils {
@ -258,7 +261,10 @@ object ImageUtils {
if (width != null && width > 0) {
val transformUrlX2 = addLimitWidth(url, width * 2)
val transformUrlX1 = addLimitWidth(url, width)
if (NetworkUtils.isWifiOr4GConnected(context)) {
// 当网络为 WIFI 或 4G 且系统版本大于 5.0 && 手机内存大于 1G 才用高清图片
if (NetworkUtils.isWifiOr4GConnected(context)
&& Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP
&& DeviceUtils.getTotalRamSizeOfDevice(context) > 1000) {
transformUrl = transformUrlX2
} else {
// 检查X2大图是否被缓存
@ -289,6 +295,24 @@ object ImageUtils {
}
}
@JvmStatic
fun bmpToByteArray(bmp: Bitmap, needRecycle: Boolean): ByteArray {
val output = ByteArrayOutputStream()
bmp.compress(Bitmap.CompressFormat.PNG, 100, output)
if (needRecycle) {
bmp.recycle()
}
val result = output.toByteArray()
try {
output.close()
} catch (e: Exception) {
e.printStackTrace()
}
return result
}
@JvmStatic
fun display(draweeView: SimpleDraweeView, @DrawableRes res: Int?) {

View File

@ -70,9 +70,7 @@ public class InstallUtils {
if (!downloadEntity.isPluggable() || PackageUtils.isSignature(context, packageName)) {
EventBus.getDefault().post(new EBPackage("安装", packageName));
}
}
}
}
for (String key : keys) {
@ -109,7 +107,7 @@ public class InstallUtils {
if (mInstance == null) {
synchronized (InstallUtils.class) {
if (mInstance == null) {
mInstance = new InstallUtils(context);
mInstance = new InstallUtils(context.getApplicationContext());
}
}
}

View File

@ -318,6 +318,9 @@ public class LoginUtils {
case 403016:
Utils.toast(context, "内容违规,请修改后再保存");
break;
case 403021:
Utils.toast(context, "内容可能包含敏感信息,请修改后再提交");
break;
case 403801:
Utils.toast(context, "获取验证码太频繁,请稍后再试");
break;

View File

@ -11,11 +11,11 @@ import android.graphics.Matrix;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.Gravity;
import android.view.KeyEvent;
import android.support.v4.content.*;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
@ -28,19 +28,17 @@ import com.gh.common.constant.Config;
import com.gh.gamecenter.R;
import com.lightgame.utils.Utils;
import com.tencent.connect.share.QQShare;
import com.tencent.mm.sdk.openapi.IWXAPI;
import com.tencent.mm.sdk.openapi.SendMessageToWX;
import com.tencent.mm.sdk.openapi.WXAPIFactory;
import com.tencent.mm.sdk.openapi.WXImageObject;
import com.tencent.mm.sdk.openapi.WXMediaMessage;
import com.tencent.mm.sdk.platformtools.Util;
import com.tencent.mm.opensdk.modelmsg.SendMessageToWX;
import com.tencent.mm.opensdk.modelmsg.WXImageObject;
import com.tencent.mm.opensdk.modelmsg.WXMediaMessage;
import com.tencent.mm.opensdk.openapi.IWXAPI;
import com.tencent.mm.opensdk.openapi.WXAPIFactory;
import com.tencent.tauth.IUiListener;
import com.tencent.tauth.Tencent;
import com.tencent.tauth.UiError;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;
@ -308,7 +306,7 @@ public class MessageShareUtils {
req.scene = SendMessageToWX.Req.WXSceneTimeline;
Bitmap compressBp = compressBitmap(shareBm);
msg.thumbData = Util.bmpToByteArray(compressBp, true);
msg.thumbData = ImageUtils.bmpToByteArray(compressBp, true);
mIWXAPI.sendReq(req);
if (mPopupWindow == null) return;
@ -376,7 +374,7 @@ public class MessageShareUtils {
}
}
}
} catch (FileNotFoundException e) {
} catch (Exception e) {
Utils.log("消息分享异常" + e.toString());
e.printStackTrace();
} finally {

View File

@ -1,18 +1,18 @@
package com.gh.common.util
import java.math.BigDecimal
import java.text.DecimalFormat
object NumberUtils {
@JvmStatic
fun transSimpleCount(count: Int): String {
val s: String
if (count > 10000) {
s = if (count > 100000) {
val number = count / 10000f
val bd = BigDecimal(number.toDouble())
s = bd.setScale(1, BigDecimal.ROUND_DOWN).toString() + "W"
val fmt = DecimalFormat("#")
fmt.format(number) + ""
} else {
s = count.toString()
count.toString()
}
return s
}

View File

@ -37,12 +37,11 @@ import com.sina.weibo.sdk.WbSdk;
import com.sina.weibo.sdk.auth.AuthInfo;
import com.tencent.connect.share.QQShare;
import com.tencent.connect.share.QzoneShare;
import com.tencent.mm.sdk.openapi.IWXAPI;
import com.tencent.mm.sdk.openapi.SendMessageToWX;
import com.tencent.mm.sdk.openapi.WXAPIFactory;
import com.tencent.mm.sdk.openapi.WXMediaMessage;
import com.tencent.mm.sdk.openapi.WXWebpageObject;
import com.tencent.mm.sdk.platformtools.Util;
import com.tencent.mm.opensdk.modelmsg.SendMessageToWX;
import com.tencent.mm.opensdk.modelmsg.WXMediaMessage;
import com.tencent.mm.opensdk.modelmsg.WXWebpageObject;
import com.tencent.mm.opensdk.openapi.IWXAPI;
import com.tencent.mm.opensdk.openapi.WXAPIFactory;
import com.tencent.tauth.IUiListener;
import com.tencent.tauth.Tencent;
import com.tencent.tauth.UiError;
@ -296,10 +295,10 @@ public class ShareUtils {
protected void onNewResultImpl(Bitmap bitmap) {
Bitmap compressBp = compressBitmap(bitmap);
if (mShareType == ShareType.askNormal || mShareType == ShareType.askInvite) {
msg.thumbData = Util.bmpToByteArray(compressBp, true);
msg.thumbData = ImageUtils.bmpToByteArray(compressBp, true);
} else {
Bitmap resultBp = addBackGround(compressBp);
msg.thumbData = Util.bmpToByteArray(resultBp, true);
msg.thumbData = ImageUtils.bmpToByteArray(resultBp, true);
}
mIWXAPI.sendReq(req);
}

View File

@ -1,5 +1,6 @@
package com.gh.common.util
import android.annotation.SuppressLint
import android.graphics.BitmapFactory
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.FileRequestBody
@ -18,6 +19,7 @@ import okhttp3.ResponseBody
import org.json.JSONObject
import java.io.File
object UploadImageUtils {
enum class UploadType {
@ -27,7 +29,7 @@ object UploadImageUtils {
icon
}
// 不处理图片,只是单纯的上
// 不处理图片,只是单纯的上
fun uploadImage(type: UploadType, imgPath: String, listener: OnUploadImageListener): Disposable {
return Single.just(imgPath)
.subscribeOn(Schedulers.computation())
@ -99,7 +101,9 @@ object UploadImageUtils {
})
}
fun compressAndUploadImageList(type: UploadType, imgs: List<String>, compressGif: Boolean, listener: OnUploadImageListListener) {
@SuppressLint("CheckResult")
fun compressAndUploadImageList(type: UploadType, imgs: List<String>, compressGif: Boolean, listener: OnUploadImageListListener): Disposable? {
var subscription: Disposable? = null
val postImageList = HashMap<String, String>()
Observable.create(ObservableOnSubscribe<Map<String, String>> {
@ -110,9 +114,12 @@ object UploadImageUtils {
listTotal += img.length()
}
for (img in compressList) {
if (subscription?.isDisposed == true) return@ObservableOnSubscribe
val requestBody = FileRequestBody<ResponseBody>(img, object : RetrofitCallback<ResponseBody>() {
override fun onProgress(total: Long, progress: Long) {
listener.onProgress(listTotal, listProgress + progress)
if (subscription?.isDisposed != true) {
listener.onProgress(listTotal, listProgress + progress)
}
}
})
val part = MultipartBody.Part.createFormData("Filedata", getFileName(img), requestBody)
@ -120,6 +127,7 @@ object UploadImageUtils {
.uploadApi.uploadImage(part, type.name)
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
if (subscription?.isDisposed == true) return
val string = data.string()
if (!string.isNullOrEmpty()) {
val url = JSONObject(string).getString("url")
@ -134,6 +142,7 @@ object UploadImageUtils {
}
override fun onFailure(exception: Exception) {
if (subscription?.isDisposed == true) return
it.onError(exception)
}
})
@ -145,6 +154,7 @@ object UploadImageUtils {
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Observer<Map<String, String>> {
override fun onSubscribe(d: Disposable) {
subscription = d
}
override fun onComplete() {
@ -162,6 +172,7 @@ object UploadImageUtils {
override fun onError(e: Throwable) {
}
})
return subscription
}
// 同步调用->避免在主线程调用以免阻塞主线程

View File

@ -327,10 +327,6 @@ public class RichEditor extends WebView {
ImageUtils.getDefaultGifRule() + IMAGE_FLAG_DEFAULT + "')");
}
public void setFocusByEnd() {
exec("javascript:RE.setFocusByEnd()");
}
public void replaceDfImageByUrl(String imgUrl) {
exec("javascript:RE.replaceDfImageByUrl('" + imgUrl + "','" +
ImageUtils.getLimitWidthRule(mDefaultImageWidth) + IMAGE_FLAG_DEFAULT + "','" +
@ -373,6 +369,86 @@ public class RichEditor extends WebView {
exec("javascript:RE.focus();");
}
public void insertLink(String href, String title) {
exec("javascript:RE.prepareInsert();");
exec("javascript:RE.insertLink('" + href + "', '" + title + "');");
}
public void removeFormat() {
exec("javascript:RE.removeFormat();");
}
public void setHeading(int heading) {
exec("javascript:RE.setHeading('" + heading + "');");
}
public void setIndent() {
exec("javascript:RE.setIndent();");
}
public void setOutdent() {
exec("javascript:RE.setOutdent();");
}
public void setAlignLeft() {
exec("javascript:RE.setJustifyLeft();");
}
public void setAlignCenter() {
exec("javascript:RE.setJustifyCenter();");
}
public void setAlignRight() {
exec("javascript:RE.setJustifyRight();");
}
public void setBlockquote() {
exec("javascript:RE.setBlockquote();");
}
public void setBullets() {
exec("javascript:RE.setBullets();");
}
public void setNumbers() {
exec("javascript:RE.setNumbers();");
}
public void undo() {
exec("javascript:RE.undo();");
}
public void redo() {
exec("javascript:RE.redo();");
}
public void setBold() {
exec("javascript:RE.setBold();");
}
public void setItalic() {
exec("javascript:RE.setItalic();");
}
public void setSubscript() {
exec("javascript:RE.setSubscript();");
}
public void setSuperscript() {
exec("javascript:RE.setSuperscript();");
}
public void setStrikeThrough() {
exec("javascript:RE.setStrikeThrough();");
}
public void setUnderline() {
exec("javascript:RE.setUnderline();");
}
public void formatBlock() {
exec("javascript:RE.formatBlock();");
}
public String getText() {
return AskUtils.stripHtml(mContents);

View File

@ -0,0 +1,30 @@
package com.gh.common.view
import android.graphics.Rect
import android.support.v7.widget.RecyclerView
import android.view.View
class SpacingItemDecoration(
var onlyDecorateTheFirstItem: Boolean = false,
var notDecorateTheFirstItem: Boolean = false,
var notDecorateTheLastItem: Boolean = false,
var left: Int = 0,
var top: Int = 0,
var right: Int = 0,
var bottom: Int = 0)
: RecyclerView.ItemDecoration() {
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State?) {
if (onlyDecorateTheFirstItem) {
if (parent.getChildAdapterPosition(view) == 0) outRect.set(left, top, right, bottom)
} else {
if (parent.getChildAdapterPosition(view) == 0 && notDecorateTheFirstItem) {
outRect.set(0, 0, 0, 0)
} else if (parent.getChildAdapterPosition(view) == parent.adapter.itemCount - 1 && notDecorateTheLastItem) {
outRect.set(0, 0, 0, 0)
} else {
outRect.set(left, top, right, bottom)
}
}
}
}

View File

@ -39,12 +39,12 @@ public class CommentDetailActivity extends NormalActivity {
public static Intent getCommunityArticleCommentIntent(Context context,
String articleId,
String articleCommentId,
String articleCommunityId,
String communityId,
LinkEntity linkEntity) {
Bundle args = new Bundle();
args.putString(CommentActivity.ARTICLE_ID, articleId);
args.putString(EntranceUtils.KEY_ARTICLE_COMMENT_ID, articleCommentId);
args.putString(CommentActivity.ARTICLE_COMMUNITY_ID, articleCommunityId);
args.putString(CommentActivity.COMMUNITY_ID, communityId);
args.putParcelable(EntranceUtils.KEY_LINK, linkEntity);
return getTargetIntent(context, CommentDetailActivity.class, CommentConversationFragment.class, args);
}

View File

@ -27,12 +27,12 @@ import android.widget.TextView;
import com.gh.base.AppUncaughtHandler;
import com.gh.base.BaseActivity;
import com.gh.base.fragment.BaseFragment_ViewPager;
import com.gh.common.AppExecutor;
import com.gh.common.constant.Config;
import com.gh.common.exposure.ExposureUtils;
import com.gh.common.exposure.meta.MetaUtil;
import com.gh.common.im.ImManager;
import com.gh.common.util.ClassUtils;
import com.gh.common.util.CommunityHelper;
import com.gh.common.util.ConcernUtils;
import com.gh.common.util.DataCollectionUtils;
import com.gh.common.util.DataLogUtils;
@ -136,7 +136,6 @@ public class MainActivity extends BaseActivity {
private boolean isSkipped = false;
public static boolean isNewFirstLaunch;
public static boolean openCommunityWithDefaultIdForTheFirsTime; // 是否根据 META-INFO 里的 JSON 自动选择默认的社区 ID
private Handler handler = new Handler();
// 黄壮华 添加观察者 修改2015/8/15
@ -260,7 +259,12 @@ public class MainActivity extends BaseActivity {
isNewFirstLaunch = mSp.getBoolean("isNewFirstLaunchV" + PackageUtils.getVersionName(), true);
if (isNewFirstLaunch) {
LogUtils.uploadDevice(DeviceTokenUtils.getLaunchType());
// 延时两秒提交 APP 启动日志的,避免提交时还没获取到 GID
AppExecutor.getUiExecutor().executeWithDelay(() -> {
if (!this.isFinishing()) {
LogUtils.uploadDevice(DeviceTokenUtils.getLaunchType());
}
}, 2000L);
getPluginUpdate();
sendActivationInfo();
mSp.edit().putBoolean("isNewFirstLaunchV" + PackageUtils.getVersionName(), false).apply();
@ -306,9 +310,6 @@ public class MainActivity extends BaseActivity {
handler.postDelayed(ImManager::attachIm, 1000);
}
// 获取可用(没有被隐藏的)的社区列表
CommunityHelper.getAvailableCommunityList();
if (getIntent().getBooleanExtra(SWITCH_TO_COMMUNITY, false)) {
handler.postDelayed(this::switchToCommunityTabAndRefresh, 800);
}
@ -707,7 +708,6 @@ public class MainActivity extends BaseActivity {
InnerMetaInfoEntity info = gson.fromJson(reader, InnerMetaInfoEntity.class);
if (info != null) {
if (EntranceUtils.HOST_COMMUNITY.equals(info.getType())) {
openCommunityWithDefaultIdForTheFirsTime = true;
UserManager.getInstance().setCommunityData(new CommunityEntity(info.getLink(), info.getText()));
runOnUiThread(() -> mMainWrapperFragment.setCurrentItem(MainWrapperFragment.INDEX_ASK));
} else {

View File

@ -38,10 +38,13 @@ import com.gh.common.util.DialogUtils;
import com.gh.common.util.DirectUtils;
import com.gh.common.util.DisplayUtils;
import com.gh.common.util.EntranceUtils;
import com.gh.common.util.GsonUtils;
import com.gh.common.util.ImageUtils;
import com.gh.common.util.MtaHelper;
import com.gh.common.util.NetworkUtils;
import com.gh.common.util.PackageUtils;
import com.gh.common.util.UploadImageUtils;
import com.gh.gamecenter.entity.ErrorEntity;
import com.gh.gamecenter.entity.InstallGameEntity;
import com.gh.gamecenter.entity.SettingsEntity;
import com.gh.gamecenter.entity.SuggestionTypeEntity;
@ -245,10 +248,11 @@ public class SuggestionActivity extends BaseActivity implements OnRequestCallBac
mAdTv.setVisibility(View.VISIBLE);
mAdTv.setText(ad.getTitle());
mAdTv.setOnClickListener(v -> {
MtaHelper.onEvent("广告位统计", "意见反馈_功能收录", ad.getTitle());
DirectUtils.directToLinkPage(this,
ad.toLinkEntity(),
"意见反馈",
"意见反馈" + mSuggestType.getType());
"(意见反馈)",
"意见反馈-功能收录-广告位");
});
}
@ -672,10 +676,7 @@ public class SuggestionActivity extends BaseActivity implements OnRequestCallBac
}
}
RequestBody body = RequestBody.create(MediaType.parse("application/json"),
jsonObject.toString());
sendSuggestion(body);
sendSuggestion(jsonObject);
if (CheckLoginUtils.isLogin()) {
// 创建一条信息至七陌客服
@ -684,8 +685,10 @@ public class SuggestionActivity extends BaseActivity implements OnRequestCallBac
}
}
private void sendSuggestion(final RequestBody body) {
private void sendSuggestion(JSONObject jsonObject) {
RequestBody body = RequestBody.create(MediaType.parse("application/json"),
jsonObject.toString());
RetrofitManager.getInstance(this).getApi().postSuggestion(body)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
@ -716,15 +719,31 @@ public class SuggestionActivity extends BaseActivity implements OnRequestCallBac
try {
if (e != null && e.code() == 403) {
String string = e.response().errorBody().string();
JSONObject object = new JSONObject(string);
int code = object.getInt("code");
if (code == 403052) {
ErrorEntity error = GsonUtils.fromJson(string, ErrorEntity.class);
if (error.getCode() == 403052) {
DialogUtils.showAlertDialog(SuggestionActivity.this, "提醒", "你已经提交过相同的反馈了"
, "关闭提交", "返回修改", () -> {
setResult(SUGGEST_TYPE_REQUEST);
finish();
}, null);
return;
} else if (error.getCode() == 403062) {
DialogUtils.showAlertDialog(SuggestionActivity.this,
"提示", "光环助手已收录游戏:" + error.getData().getGameName(),
"查看游戏", "仍然提交", () -> {
GameDetailActivity.startGameDetailActivity(SuggestionActivity.this,
error.getData().getGameId(), "(意见反馈-游戏收录-存在相同游戏)");
}, () -> {
try {
jsonObject.put("again", true);
} catch (Exception e1) {
e1.printStackTrace();
}
postDialog = WaitingDialogFragment.newInstance(getString(R.string.dialog_feedback_doing));
postDialog.show(getSupportFragmentManager(), null);
sendSuggestion(jsonObject);
});
return;
}
}
} catch (Exception e1) {

View File

@ -4,10 +4,14 @@ import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.AppBarLayout;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
@ -15,9 +19,12 @@ import com.gc.materialdesign.views.ProgressBarCircularIndeterminate;
import com.gh.base.BaseActivity;
import com.gh.base.OnRequestCallBackListener;
import com.gh.common.util.EntranceUtils;
import com.gh.common.util.TextHelper;
import com.gh.common.view.VerticalItemDecoration;
import com.gh.gamecenter.adapter.ToolBoxRvAdapter;
import com.gh.gamecenter.suggest.SuggestType;
import com.lightgame.utils.Util_System_Keyboard;
import com.lightgame.utils.Utils;
import butterknife.BindView;
import butterknife.OnClick;
@ -27,8 +34,16 @@ import butterknife.OnClick;
*/
public class ToolBoxActivity extends BaseActivity implements SwipeRefreshLayout.OnRefreshListener,
ToolBoxRvAdapter.OnSearchCallBackListener, OnRequestCallBackListener {
OnRequestCallBackListener {
@BindView(R.id.et_search)
public EditText searchEt;
@BindView(R.id.tv_search)
public TextView searchTv;
@BindView(R.id.tv_back)
public TextView backTv;
@BindView(R.id.toolbox_appbar)
AppBarLayout mAppBar;
@BindView(R.id.toolbox_rv)
RecyclerView mToolboxRv;
@BindView(R.id.reuse_none_data)
@ -46,16 +61,10 @@ public class ToolBoxActivity extends BaseActivity implements SwipeRefreshLayout.
private ToolBoxRvAdapter mRvAdapter;
private ToolBoxRvAdapter mNormalRvAdapter;
private boolean mIsSearch; // 记录页面状态 搜索页面/普通页面
private String mSearchKey; // 记录搜索关键字
Runnable runnable = new Runnable() {
@Override
public void run() {
changeAdapter(true);
}
};
Runnable runnable = () -> changeAdapter(true);
@NonNull
public static Intent getIntent(Context context, String entrance) {
@ -64,7 +73,6 @@ public class ToolBoxActivity extends BaseActivity implements SwipeRefreshLayout.
return intent;
}
@Override
protected int getLayoutId() {
return R.layout.activity_toolbox;
@ -81,7 +89,7 @@ public class ToolBoxActivity extends BaseActivity implements SwipeRefreshLayout.
mLayoutManager = new LinearLayoutManager(this);
mToolboxRv.setLayoutManager(mLayoutManager);
mRvAdapter = new ToolBoxRvAdapter(this, this, ToolBoxActivity.this, mIsSearch, mSearchKey);
mRvAdapter = new ToolBoxRvAdapter(this, this, mIsSearch, mSearchKey);
mToolboxRv.addItemDecoration(new VerticalItemDecoration(this, 8, false));
mToolboxRv.setAdapter(mRvAdapter);
@ -99,8 +107,52 @@ public class ToolBoxActivity extends BaseActivity implements SwipeRefreshLayout.
}
}
});
mAppBar.addOnOffsetChangedListener((appBarLayout, verticalOffset) -> {
if (verticalOffset == 0) {
mRefresh.setEnabled(true);
} else {
mRefresh.setEnabled(false);
}
int totalScrollRange = appBarLayout.getTotalScrollRange();
if (totalScrollRange == -verticalOffset) {
Util_System_Keyboard.hideSoftKeyboard(this);
}
});
initSearch();
}
private void initSearch() {
backTv.setOnClickListener(v -> search(false, searchEt.getText().toString()));
TextHelper.limitTheLengthOfEditText(searchEt, 20, () -> {
Utils.toast(this, "最多输入20字");
});
searchTv.setOnClickListener(v -> {
if (TextUtils.isEmpty(searchEt.getText().toString())) {
Utils.toast(this, R.string.search_hint);
return;
}
search(true, searchEt.getText().toString());
});
searchEt.setOnFocusChangeListener((v, hasFocus) -> {
if (!hasFocus) {
Util_System_Keyboard.hideSoftKeyboard(this, searchEt);
}
});
searchEt.setOnEditorActionListener((v, actionId, event) -> {
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
searchTv.performClick();
}
return false;
});
}
@OnClick({R.id.reuse_no_connection, R.id.reuse_none_data})
public void onClick(View view) {
if (view.getId() == R.id.reuse_no_connection) {
@ -113,7 +165,6 @@ public class ToolBoxActivity extends BaseActivity implements SwipeRefreshLayout.
SuggestionActivity.startSuggestionActivity(this, SuggestType.functionSuggest, null, null);
}
}
}
@Override
@ -122,7 +173,6 @@ public class ToolBoxActivity extends BaseActivity implements SwipeRefreshLayout.
mNoneData.setVisibility(View.GONE);
mNoConnection.setVisibility(View.GONE);
mLoading.setVisibility(View.GONE);
}
@Override
@ -156,7 +206,6 @@ public class ToolBoxActivity extends BaseActivity implements SwipeRefreshLayout.
mRefresh.postDelayed(runnable, 1000);
}
@Override
public void search(boolean isSearch, String searchKey) {
if (mNoneData.getVisibility() == View.VISIBLE) {
mNoneData.setVisibility(View.GONE);
@ -171,15 +220,26 @@ public class ToolBoxActivity extends BaseActivity implements SwipeRefreshLayout.
private void changeAdapter(boolean isRefresh) {
if (mIsSearch) {
mRvAdapter = new ToolBoxRvAdapter(this, this, this, mIsSearch, mSearchKey);
mRvAdapter = new ToolBoxRvAdapter(this, this, mIsSearch, mSearchKey);
} else {
if (mNormalRvAdapter != null && !isRefresh) {
mRvAdapter = mNormalRvAdapter;
} else {
mRvAdapter = new ToolBoxRvAdapter(this, this, this, mIsSearch, null);
mRvAdapter = new ToolBoxRvAdapter(this, this, mIsSearch, null);
mNormalRvAdapter = mRvAdapter;
}
}
mToolboxRv.setAdapter(mRvAdapter);
if (mSearchKey != null) {
searchEt.setText(mSearchKey);
searchEt.setSelection(searchEt.getText().length());
}
if (mIsSearch) {
backTv.setVisibility(View.VISIBLE);
} else {
backTv.setVisibility(View.GONE);
}
}
}

View File

@ -75,17 +75,21 @@ public class ImagePagerAdapter extends RecyclingPagerAdapter {
view.setOnClickListener(v -> {
int size = mSlideEntityList.size();
if (size == 0) return;
// 首页轮播图数据统计
DataLogUtils.uploadLunbotuLog(mContext, slideEntity.getType(),
slideEntity.getText(), String.valueOf(getPosition(position) % mSlideEntityList.size() + 1));
slideEntity.getText(), String.valueOf(getPosition(position) % size + 1));
String entrance = StringUtils.buildString("(游戏-专题:滚动图["
, slideEntity.getText()
, "=", slideEntity.getType()
, "=", String.valueOf(getPosition(position) + 1)
, "=", String.valueOf(size + 1)
, "])");
DataUtils.onMtaEvent(mContext, "轮播图", mSource, String.valueOf(getPosition(position) % mSlideEntityList.size() + 1));
DataUtils.onMtaEvent(mContext, "轮播图", mSource, String.valueOf(getPosition(position) % size + 1));
DirectUtils.directToLinkPage(mContext, slideEntity, entrance, "首页游戏");

View File

@ -20,6 +20,7 @@ import com.gh.common.util.DisplayUtils;
import com.gh.common.util.EntranceUtils;
import com.gh.common.util.ImageUtils;
import com.gh.common.util.NewsUtils;
import com.gh.common.util.NumberUtils;
import com.gh.common.util.StringUtils;
import com.gh.common.util.TimestampUtils;
import com.gh.gamecenter.NewsDetailActivity;
@ -247,14 +248,10 @@ public class MessageDetailAdapter extends BaseRecyclerAdapter<ViewHolder> {
private void initNewsDigestViewHolder(final NewsDigestViewHolder viewHolder) {
if (mConcernEntity.getViews() != 0) {
viewHolder.readNum.setText(String.valueOf(mConcernEntity.getViews()));
viewHolder.readNum.setText(NumberUtils.transSimpleCount(mConcernEntity.getViews()));
}
if (mConcernEntity.getCommentnum() > 999) {
viewHolder.commentnum.setText(R.string.thousand);
} else {
viewHolder.commentnum.setText(String.valueOf(mConcernEntity.getCommentnum()));
}
viewHolder.commentnum.setText(NumberUtils.transSimpleCount(mConcernEntity.getCommentnum()));
if (mConcernEntity.getBrief() != null) {
viewHolder.content.setText(Html.fromHtml(mConcernEntity.getBrief()));

View File

@ -3,12 +3,8 @@ package com.gh.gamecenter.adapter;
import android.content.Context;
import android.content.Intent;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.TextView;
import com.gh.base.OnRequestCallBackListener;
import com.gh.common.util.ImageUtils;
@ -19,16 +15,12 @@ import com.gh.gamecenter.SuggestionActivity;
import com.gh.gamecenter.WebActivity;
import com.gh.gamecenter.adapter.viewholder.FooterViewHolder;
import com.gh.gamecenter.adapter.viewholder.ReuseViewHolder;
import com.gh.gamecenter.adapter.viewholder.SearchViewHolder;
import com.gh.gamecenter.adapter.viewholder.ToolBoxViewHolder;
import com.gh.gamecenter.entity.ToolBoxEntity;
import com.gh.gamecenter.manager.UserManager;
import com.gh.gamecenter.retrofit.Response;
import com.gh.gamecenter.retrofit.RetrofitManager;
import com.gh.gamecenter.suggest.SuggestType;
import com.lightgame.adapter.BaseRecyclerAdapter;
import com.lightgame.utils.Util_System_Keyboard;
import com.lightgame.utils.Utils;
import java.util.ArrayList;
import java.util.List;
@ -47,29 +39,23 @@ import static com.gh.gamecenter.R.string.loading;
public class ToolBoxRvAdapter extends BaseRecyclerAdapter {
private OnRequestCallBackListener mCallBackListener;
private OnSearchCallBackListener mSearchListener;
private List<ToolBoxEntity> mEntityList;
private String mSearchKey;
private String mToken;
// private boolean mLoadConcernDataOver;
private boolean mIsSearch;
private boolean mIsLoading;
private boolean mIsOver;
private boolean mIsNetworkError;
private int mPage;
public ToolBoxRvAdapter(Context context, OnRequestCallBackListener listener, OnSearchCallBackListener searchListener,
boolean isSearch, String key) {
public ToolBoxRvAdapter(Context context, OnRequestCallBackListener listener, boolean isSearch, String key) {
super(context);
this.mIsSearch = isSearch;
this.mSearchKey = key;
mPage = 1;
mToken = UserManager.getInstance().getToken();
mSearchListener = searchListener;
mCallBackListener = listener;
mEntityList = new ArrayList<>();
loadData();
@ -121,31 +107,9 @@ public class ToolBoxRvAdapter extends BaseRecyclerAdapter {
});
}
// 去除重复数据(普通列表排除关注数据)
private static List<ToolBoxEntity> removeDuplicateData(List<ToolBoxEntity> sourceList, List<ToolBoxEntity> rawList) {
if (sourceList == null || sourceList.isEmpty()
|| rawList == null || rawList.isEmpty()) {
return rawList;
}
String id;
for (int i = 0; i < rawList.size(); i++) {
id = rawList.get(i).getId();
for (ToolBoxEntity toolBoxEntity : sourceList) {
if (id.equals(toolBoxEntity.getId())) {
rawList.remove(i);
i--;
break;
}
}
}
return rawList;
}
@Override
public int getItemViewType(int position) {
if (position == 0) {
return 0;
} else if (position == 1) {
return 1;
} else if (position == getItemCount() - 1) {
return 2;
@ -156,10 +120,7 @@ public class ToolBoxRvAdapter extends BaseRecyclerAdapter {
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == 0) {
View view = mLayoutInflater.inflate(R.layout.layout_search_bar, parent, false);
return new SearchViewHolder(view);
} else if (viewType == 2) {
if (viewType == 2) {
View view = mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false);
return new FooterViewHolder(view);
} else if (viewType == 1) {
@ -176,83 +137,26 @@ public class ToolBoxRvAdapter extends BaseRecyclerAdapter {
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof ToolBoxViewHolder) {
ToolBoxViewHolder viewHolder = (ToolBoxViewHolder) holder;
ToolBoxEntity toolBoxEntity = mEntityList.get(position - 2);
ToolBoxEntity toolBoxEntity = mEntityList.get(position - 1);
initToolBoxViewHolder(viewHolder, toolBoxEntity);
} else if (holder instanceof FooterViewHolder) {
FooterViewHolder viewHolder = (FooterViewHolder) holder;
initFooterViewHolder(viewHolder);
} else if (holder instanceof SearchViewHolder) {
SearchViewHolder viewHolder = (SearchViewHolder) holder;
initSearchViewHolder(viewHolder);
} else if (holder instanceof ReuseViewHolder) {
holder.itemView.setOnClickListener(v -> SuggestionActivity.startSuggestionActivity(mContext, SuggestType.functionSuggest, null, null));
holder.itemView.setOnClickListener(v -> SuggestionActivity.startSuggestionActivity(mContext, SuggestType.normal, null, null));
}
}
@Override
public int getItemCount() {
if (mEntityList.size() > 0) {
return mEntityList.size() + 3;
return mEntityList.size() + 2;
} else {
return 1;
return 0;
}
}
private void initSearchViewHolder(final SearchViewHolder viewHolder) {
if (mSearchKey != null) {
viewHolder.searchEt.setText(mSearchKey);
}
if (mIsSearch) {
viewHolder.backTv.setVisibility(View.VISIBLE);
} else {
viewHolder.backTv.setVisibility(View.GONE);
}
viewHolder.backTv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mSearchListener.search(false, viewHolder.searchEt.getText().toString());
}
});
viewHolder.searchTv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (TextUtils.isEmpty(viewHolder.searchEt.getText().toString())) {
Utils.toast(mContext, R.string.search_hint);
return;
}
mSearchListener.search(true, viewHolder.searchEt.getText().toString());
}
});
viewHolder.searchEt.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
Util_System_Keyboard.hideSoftKeyboard(mContext, viewHolder.searchEt);
}
}
});
viewHolder.searchEt.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
viewHolder.searchTv.performClick();
}
return false;
}
});
}
private void initFooterViewHolder(FooterViewHolder viewHolder) {
viewHolder.initItemPadding();
if (mIsNetworkError) {
@ -261,12 +165,7 @@ public class ToolBoxRvAdapter extends BaseRecyclerAdapter {
viewHolder.loading.setVisibility(View.GONE);
viewHolder.hint.setText(R.string.loading_failed_retry);
viewHolder.itemView.setClickable(true);
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
loadData();
}
});
viewHolder.itemView.setOnClickListener(v -> loadData());
} else if (mIsOver) {
viewHolder.lineLeft.setVisibility(View.VISIBLE);
viewHolder.lineRight.setVisibility(View.VISIBLE);
@ -287,26 +186,19 @@ public class ToolBoxRvAdapter extends BaseRecyclerAdapter {
viewHolder.mTitle.setText(toolBoxEntity.getName());
ImageUtils.display(viewHolder.mGameThumb, toolBoxEntity.getIcon());
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String url = toolBoxEntity.getUrl();
viewHolder.itemView.setOnClickListener(v -> {
String url = toolBoxEntity.getUrl();
// http://www.ghzs666.com/article/59291e7ce9a64a496cfd6897.html
if (url != null && url.contains(URL_ARTICLE)) {
String newsId = url.substring(url.lastIndexOf("/") + 1, url.length() - 5); // 5: ".html"
Intent intent = NewsDetailActivity.getIntentById(mContext, newsId, "工具箱列表");
mContext.startActivity(intent);
} else {
mContext.startActivity(WebActivity.getWebByCollectionTools(mContext, toolBoxEntity, false));
}
if (url != null && url.contains(URL_ARTICLE)) {
String newsId = url.substring(url.lastIndexOf("/") + 1, url.length() - 5); // 5: ".html"
Intent intent = NewsDetailActivity.getIntentById(mContext, newsId, "工具箱列表");
mContext.startActivity(intent);
} else {
mContext.startActivity(WebActivity.getWebByCollectionTools(mContext, toolBoxEntity, false));
}
});
}
public int dataSize() {
return mEntityList.size();
}
public boolean isOver() {
return mIsOver;
}
@ -318,8 +210,4 @@ public class ToolBoxRvAdapter extends BaseRecyclerAdapter {
public boolean isNetworkError() {
return mIsNetworkError;
}
public interface OnSearchCallBackListener {
void search(boolean isSearch, String searchKey);
}
}

View File

@ -32,7 +32,7 @@ import io.reactivex.Observable;
public abstract class ListFragment<T, VM extends BaseListViewModel /* 该泛型位置对应getViewModelClass */> extends NormalFragment implements
Observer<List<T>>,
SwipeRefreshLayout.OnRefreshListener,
OnDataObservable {
OnDataObservable<T> {
@BindView(R.id.list_rv)
protected RecyclerView mListRv;

View File

@ -15,6 +15,7 @@ import io.reactivex.Observable;
public class NormalListViewModel<T> extends ListViewModel<T, T> {
// TODO 作为构造函数从外部传入会引起内存泄漏,当 View 被销毁时,这个类的实例还会持有原有 View 的引用
private OnDataObservable mDataObservable;
public NormalListViewModel(@NonNull Application application, OnDataObservable dataObservable) {

View File

@ -16,6 +16,7 @@ import com.gh.common.constant.ItemViewType;
import com.gh.common.util.DisplayUtils;
import com.gh.common.util.ImageUtils;
import com.gh.common.util.NewsUtils;
import com.gh.common.util.NumberUtils;
import com.gh.gamecenter.R;
import com.gh.gamecenter.adapter.viewholder.FooterViewHolder;
import com.gh.gamecenter.adapter.viewholder.NewsImage1ViewHolder;
@ -145,7 +146,7 @@ public class ArticleAdapter extends ListAdapter<NewsEntity> {
viewHolder.read.setVisibility(View.GONE);
} else {
viewHolder.read.setVisibility(View.VISIBLE);
viewHolder.read.setText(String.format(Locale.getDefault(), "阅读 %d", views));
viewHolder.read.setText(String.format(Locale.getDefault(), "阅读 %s", NumberUtils.transSimpleCount(views)));
}
NewsUtils.setNewsType(viewHolder.type, newsEntity.getType(), newsEntity.getPriority(), position);
}
@ -187,7 +188,7 @@ public class ArticleAdapter extends ListAdapter<NewsEntity> {
viewHolder.read.setVisibility(View.GONE);
} else {
viewHolder.read.setVisibility(View.VISIBLE);
viewHolder.read.setText(String.format(Locale.getDefault(), "阅读 %d", views));
viewHolder.read.setText(String.format(Locale.getDefault(), "阅读 %s", NumberUtils.transSimpleCount(views)));
}
NewsUtils.setNewsType(viewHolder.type, newsEntity.getType(), newsEntity.getPriority(), position);
}
@ -211,7 +212,7 @@ public class ArticleAdapter extends ListAdapter<NewsEntity> {
viewHolder.read.setVisibility(View.GONE);
} else {
viewHolder.read.setVisibility(View.VISIBLE);
viewHolder.read.setText(String.format(Locale.getDefault(), "阅读 %d", views));
viewHolder.read.setText(String.format(Locale.getDefault(), "阅读 %s", NumberUtils.transSimpleCount(views)));
}
NewsUtils.setNewsType(viewHolder.type, newsEntity.getType(), newsEntity.getPriority(), position);
}

View File

@ -1,12 +1,12 @@
package com.gh.gamecenter.db;
import android.content.Context;
import android.text.TextUtils;
import com.gh.gamecenter.db.info.AskSearchHistoryInfo;
import com.j256.ormlite.dao.CloseableIterator;
import com.j256.ormlite.dao.Dao;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@ -20,37 +20,45 @@ public class AskSearchHistoryDao {
try {
helper = DatabaseHelper.getHelper(context);
dao = helper.getDao(AskSearchHistoryInfo.class);
} catch (SQLException e) {
} catch (Exception e) {
e.printStackTrace();
}
}
public void add(String key, String communityId) {
try {
List<String> all = getAll(communityId);
if (!all.contains(key)) dao.createOrUpdate(new AskSearchHistoryInfo(key, communityId));
} catch (SQLException e) {
if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(communityId)) {
dao.createOrUpdate(createInfo(key, communityId));
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void delete(String item) {
private AskSearchHistoryInfo createInfo(String key, String communityId) {
try {
dao.deleteById(item);
} catch (SQLException e) {
List<AskSearchHistoryInfo> his = dao.queryBuilder().
orderBy("time", false).
where().eq("communityId", communityId).
query();
for (AskSearchHistoryInfo next : his) {
String dbKey = next.getKey();
if (dbKey != null && dbKey.equals(key)) dao.delete(next);
}
} catch (Exception e) {
e.printStackTrace();
}
return new AskSearchHistoryInfo(key, communityId);
}
public void deleteAll() {
CloseableIterator<AskSearchHistoryInfo> iterator = dao.iterator();
while (iterator.hasNext()) {
try {
dao.delete(iterator.next());
} catch (SQLException e) {
} catch (Exception e) {
e.printStackTrace();
}
@ -70,7 +78,7 @@ public class AskSearchHistoryDao {
while (hisIterator.hasNext()) {
history.add(hisIterator.next().getKey());
}
} catch (SQLException e) {
} catch (Exception e) {
e.printStackTrace();
}

View File

@ -78,7 +78,8 @@ class DiscoverFragment : BaseFragment<Any>() {
discoverAdView.setOnClickListener {
MtaHelper.onEvent("发现", "广告-${ad.title}")
DirectUtils.directToLinkPage(requireContext(), ad.toLinkEntity(), "(首页)", "(首页:发现)")
MtaHelper.onEvent("广告位统计", "发现_功能列表", ad.title)
DirectUtils.directToLinkPage(requireContext(), ad.toLinkEntity(), "(首页:发现)", "发现-广告位")
}
mDiscoverContainer.addView(discoverAdView)
}

View File

@ -1,10 +1,13 @@
package com.gh.gamecenter.entity
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.android.parcel.Parcelize
@Parcelize
data class Auth(
val text: String = "",
val color: String = "",
val icon: String = "") : Parcelable
val icon: String = "",
@SerializedName("article_id")
val articleId: String? = null) : Parcelable

View File

@ -7,5 +7,9 @@ data class ErrorEntity(var code: Int? = 0,
var toast: String? = "",
var data: Data? = null) {
data class Data(@SerializedName("always_block")
var alwaysBlock: Boolean? = false)
var alwaysBlock: Boolean? = false,
@SerializedName("game_id")
var gameId: String = "",
@SerializedName("game_name")
var gameName: String = "")
}

View File

@ -71,7 +71,9 @@ data class GameEntity(
var fixedTop: Boolean? = false,
var fixedTopHint: Boolean? = false,
@SerializedName("download_notice")
val downloadAd: LinkEntity? = null) : Parcelable {
val downloadAd: LinkEntity? = null,
// 社区名字,用于首页替换游戏曝光时使用
var subjectName: String? = null) : Parcelable {
@IgnoredOnParcel
private var entryMap: ArrayMap<String, DownloadEntity>? = ArrayMap()

View File

@ -90,15 +90,24 @@ class MeEntity(@SerializedName("is_community_voted")
const val MODERATOR_LEVEL_SUPPER = "super"
// moderator permissions
// 问题权限
const val PATCH_QUESTION_TAG = "update-question-tag" // 修改问题标签:只修改标签
const val PATCH_QUESTION = "update-question" // 修改问题:除标签以外的字段
const val HIDE_QUESTION = "hide-question" // 隐藏问题
const val GET_MODIFIED_VERSIONS = "get-modified-versions" // 查看问题的修改历史
// 回答权限
const val CHOICENESS_ANSWER = "choiceness-answer" // 将回答加入精选列表
const val FOLD_ANSWER = "fold-answer" // 折叠回答
const val HIDE_ANSWER = "hide-answer" // 隐藏回答
const val TOP_ANSWER_COMMENT = "top-answer-comment" // 置顶回答的评论
const val HIDE_ANSWER_COMMENT = "hide-answer-comment" // 隐藏回答的评论
// 文章权限
const val UPDATE_COMMUNITY_ARTICLE = "update-community-article" // 修改文章
const val CHOICENESS_COMMUNITY_ARTICLE = "choiceness-community-article" // 加精文章
const val HIDE_COMMUNITY_ARTICLE = "hide-community-article" // 隐藏文章
const val TOP_COMMUNITY_ARTICLE_COMMENT = "top-community-article-comment" // 置顶文章评论
const val HIDE_COMMUNITY_ARTICLE_COMMENT = "hide-community-article-comment" // 隐藏文章评论
}
}

View File

@ -8,7 +8,7 @@ data class PersonalHistoryEntity(
val type: String = "",
val question: Question = Question(),
val brief: String = "",
val count: Count = Count(),
var count: Count = Count(),
val time: Long = 0,
val title: String = "",
val community: CommunityEntity,
@ -23,7 +23,7 @@ data class PersonalHistoryEntity(
val title: String = "")
data class Count(
val comment: Int = -1,
var comment: Int = -1,
val vote: Int = -1,
val answer: Int = -1)

View File

@ -0,0 +1,5 @@
package com.gh.gamecenter.entity
import android.content.Intent
class ResultEntity(val requestCode: Int, val resultCode: Int, val data: Intent?)

View File

@ -14,6 +14,7 @@ import android.widget.LinearLayout
import com.facebook.drawee.controller.BaseControllerListener
import com.facebook.imagepipeline.image.ImageInfo
import com.gh.base.OnViewClickListener
import com.gh.common.AppExecutor
import com.gh.common.constant.Config
import com.gh.common.constant.ItemViewType
import com.gh.common.exposure.ExposureEvent
@ -214,14 +215,14 @@ class GameFragmentAdapter(context: Context, model: GameViewModel, var blockName:
holder.initFooterViewHolder(mLoadStatus == LoadStatus.LIST_LOADING
, mLoadStatus == LoadStatus.LIST_FAILED
, mLoadStatus == LoadStatus.LIST_OVER) {
if (mLoadStatus == LoadStatus.LIST_OVER) {
MtaHelper.onEvent("首页_点击", "底部", "点击回到顶部")
mViewModel.commandScrollTop.postValue(null)
} else {
mViewModel.getSubjectList(false)
notifyItemChanged(itemCount - 1)
}
}
if (mLoadStatus == LoadStatus.LIST_OVER) {
MtaHelper.onEvent("首页_点击", "底部", "点击回到顶部")
mViewModel.commandScrollTop.postValue(null)
} else {
mViewModel.getSubjectList(false)
notifyItemChanged(itemCount - 1)
}
}
}
private fun bindGameViewPagerView(holder: GameViewPagerViewHolder, position: Int) {
@ -291,10 +292,10 @@ class GameFragmentAdapter(context: Context, model: GameViewModel, var blockName:
val slideList = mItemDataList[position].slideList
val pagerAdapter = binding.viewPager.adapter
if (slideList != null && slideList.isNotEmpty() &&
(pagerAdapter == null ||
pagerAdapter is ImagePagerAdapter &&
pagerAdapter.dataSize == slideList.size)) {
if (slideList != null
&& slideList.isNotEmpty()
&& (pagerAdapter == null
|| (pagerAdapter is ImagePagerAdapter && pagerAdapter.dataSize != slideList.size))) {
binding.viewpagerLlHint.removeAllViews()
val margin = DisplayUtils.dip2px(mContext, 6f)
var i = 0
@ -378,7 +379,7 @@ class GameFragmentAdapter(context: Context, model: GameViewModel, var blockName:
val keyName = if (TextUtils.isEmpty(blockName)) "首页" else "板块"
val keyValue = if (TextUtils.isEmpty(blockName)) "" else blockName
itemData.exposureEvent = ExposureEvent.createEvent(gameEntity = gameEntity,
source = listOf(ExposureSource(keyName, keyValue), ExposureSource("专题", subjectData.name!!)),
source = listOf(ExposureSource(keyName, keyValue), ExposureSource("专题", gameEntity.subjectName ?: subjectData.name!!)),
eTrace = null,
event = ExposureType.EXPOSURE)
@ -467,13 +468,15 @@ class GameFragmentAdapter(context: Context, model: GameViewModel, var blockName:
entryMap[download.platform] = download
}
if (getItemViewType(gameAndPosition.position) == ItemViewType.GAME_PLUGIN) {
val adapter = mPluginViewHolder?.mPluginRv?.adapter
if (adapter is GamePluginAdapter) {
adapter.notifyItemByDownload(download)
AppExecutor.uiExecutor.execute {
if (getItemViewType(gameAndPosition.position) == ItemViewType.GAME_PLUGIN) {
val adapter = mPluginViewHolder?.mPluginRv?.adapter
if (adapter is GamePluginAdapter) {
adapter.notifyItemByDownload(download)
}
} else {
notifyItemChanged(gameAndPosition.position)
}
} else {
notifyItemChanged(gameAndPosition.position)
}
}
}
@ -502,7 +505,7 @@ class GameFragmentAdapter(context: Context, model: GameViewModel, var blockName:
}
}
} else {
if (position > mItemDataList.size) return arrayListOf()
if (position >= mItemDataList.size) return arrayListOf()
val game = mItemDataList[position].game
if (game != null) {

View File

@ -106,7 +106,12 @@ public class GameDetailBasicInfoAdapter extends BaseRecyclerAdapter<RecyclerView
viewHolder.hintDv.setVisibility(View.GONE);
}
viewHolder.hintTv.setText(tagEntity.getName());
viewHolder.hintTv.setTextColor(Color.parseColor(tagEntity.getColor()));
try {
// 有可能给的颜色有问题
viewHolder.hintTv.setTextColor(Color.parseColor(tagEntity.getColor()));
} catch (Exception ignore) {
}
if (isOpen) {
viewHolder.hintContentTv.setVisibility(View.VISIBLE);
viewHolder.hintContentTv.setText(tagEntity.getDes());
@ -124,6 +129,8 @@ public class GameDetailBasicInfoAdapter extends BaseRecyclerAdapter<RecyclerView
@Override
public int getItemCount() {
if (tags == null) return 0;
if (tips.getTitle() != null) {
return tags.size() + 1;
}

View File

@ -120,7 +120,6 @@ class RatingFragment : ListFragment<RatingComment, RatingViewModel>() {
R.id.rating_score_one -> targetScore = star.one / 2
}
var f = (targetScore / star.hits.toFloat()) * 100
if (0 < f && f < 1) {
f = 1F

View File

@ -8,10 +8,7 @@ import android.text.TextUtils
import android.view.MenuItem
import com.gh.base.BaseActivity
import com.gh.base.fragment.WaitingDialogFragment
import com.gh.common.util.DeviceUtils
import com.gh.common.util.EntranceUtils
import com.gh.common.util.ErrorHelper
import com.gh.common.util.GdtHelper
import com.gh.common.util.*
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.ActivityRatingEditBinding
import com.gh.gamecenter.entity.GameEntity
@ -114,4 +111,16 @@ class RatingEditActivity : BaseActivity() {
return intent
}
}
override fun handleBackPressed(): Boolean {
val content = mBinding?.content?.text.toString()
if (!TextUtils.isEmpty(content)) {
DialogUtils.showAlertDialog(this, "提示",
"确定退出评论吗?已撰写的内容会丢失",
"继续撰写", "确定退出",
null, { finish() })
return true
}
return super.handleBackPressed()
}
}

View File

@ -16,6 +16,7 @@ import com.gh.common.util.DisplayUtils;
import com.gh.common.util.ImageUtils;
import com.gh.common.util.LibaoUtils;
import com.gh.common.util.NewsUtils;
import com.gh.common.util.NumberUtils;
import com.gh.common.util.PlatformUtils;
import com.gh.common.util.StringUtils;
import com.gh.gamecenter.R;
@ -432,15 +433,11 @@ class ConcernAdapter extends BaseRecyclerAdapter<ViewHolder> {
int views = concernEntity.getViews();
viewHolder.readIcon.setVisibility(View.VISIBLE);
viewHolder.readNum.setText(String.valueOf(views));
viewHolder.readNum.setText(NumberUtils.transSimpleCount(views));
int commentnum = concernEntity.getCommentnum();
viewHolder.commentnum.setVisibility(View.VISIBLE);
if (commentnum > 999) {
viewHolder.commentnum.setText(R.string.thousand);
} else {
viewHolder.commentnum.setText(String.valueOf(commentnum));
}
viewHolder.commentnum.setText(NumberUtils.transSimpleCount(commentnum));
}

View File

@ -214,6 +214,8 @@ public class ConcernFragment extends NormalFragment implements SwipeRefreshLayou
}
private void initRecommendAdapter(List<GameEntity> response) {
if (!isAdded()) return;
mConcernRecommendAdapter = new MyConcernRecommendAdapter(getContext(),
new OnRequestCallBackListener() {
@Override

View File

@ -13,6 +13,7 @@ import com.gh.common.constant.ItemViewType;
import com.gh.common.util.DisplayUtils;
import com.gh.common.util.ImageUtils;
import com.gh.common.util.NewsUtils;
import com.gh.common.util.NumberUtils;
import com.gh.gamecenter.R;
import com.gh.gamecenter.adapter.viewholder.FooterViewHolder;
import com.gh.gamecenter.adapter.viewholder.NewsImage1ViewHolder;
@ -107,7 +108,7 @@ class InfoAdapter extends ListAdapter<NewsEntity> {
viewHolder.read.setVisibility(View.GONE);
} else {
viewHolder.read.setVisibility(View.VISIBLE);
viewHolder.read.setText(String.format(Locale.getDefault(), "阅读 %d", views));
viewHolder.read.setText(String.format(Locale.getDefault(), "阅读 %s", NumberUtils.transSimpleCount(views)));
}
NewsUtils.setNewsType(viewHolder.type, newsEntity.getType(), newsEntity.getPriority(), position);
}
@ -141,7 +142,7 @@ class InfoAdapter extends ListAdapter<NewsEntity> {
viewHolder.read.setVisibility(View.GONE);
} else {
viewHolder.read.setVisibility(View.VISIBLE);
viewHolder.read.setText(String.format(Locale.getDefault(), "阅读 %d", views));
viewHolder.read.setText(String.format(Locale.getDefault(), "阅读 %s", NumberUtils.transSimpleCount(views)));
}
NewsUtils.setNewsType(viewHolder.type, newsEntity.getType(), newsEntity.getPriority(), position);
}
@ -158,7 +159,7 @@ class InfoAdapter extends ListAdapter<NewsEntity> {
viewHolder.read.setVisibility(View.GONE);
} else {
viewHolder.read.setVisibility(View.VISIBLE);
viewHolder.read.setText(String.format(Locale.getDefault(), "阅读 %d", views));
viewHolder.read.setText(String.format(Locale.getDefault(), "阅读 %s", NumberUtils.transSimpleCount(views)));
}
NewsUtils.setNewsType(viewHolder.type, newsEntity.getType(), newsEntity.getPriority(), position);
}

View File

@ -11,6 +11,7 @@ import com.gh.common.constant.ItemViewType;
import com.gh.common.util.DisplayUtils;
import com.gh.common.util.ImageUtils;
import com.gh.common.util.NewsUtils;
import com.gh.common.util.NumberUtils;
import com.gh.gamecenter.R;
import com.gh.gamecenter.adapter.viewholder.FooterViewHolder;
import com.gh.gamecenter.adapter.viewholder.NewsImage1ViewHolder;
@ -102,7 +103,7 @@ class OriginalAdapter extends ListAdapter<NewsEntity> {
viewHolder.read.setVisibility(View.GONE);
} else {
viewHolder.read.setVisibility(View.VISIBLE);
viewHolder.read.setText(String.format(Locale.getDefault(), "阅读 %d", views));
viewHolder.read.setText(String.format(Locale.getDefault(), "阅读 %s", NumberUtils.transSimpleCount(views)));
}
NewsUtils.setNewsType(viewHolder.type, newsEntity.getType(), newsEntity.getPriority(), position);
}
@ -121,7 +122,7 @@ class OriginalAdapter extends ListAdapter<NewsEntity> {
viewHolder.read.setVisibility(View.GONE);
} else {
viewHolder.read.setVisibility(View.VISIBLE);
viewHolder.read.setText(String.format(Locale.getDefault(), "阅读 %d", views));
viewHolder.read.setText(String.format(Locale.getDefault(), "阅读 %s", NumberUtils.transSimpleCount(views)));
}
NewsUtils.setNewsType(viewHolder.type, newsEntity.getType(), newsEntity.getPriority(), position);
}
@ -138,7 +139,7 @@ class OriginalAdapter extends ListAdapter<NewsEntity> {
viewHolder.read.setVisibility(View.GONE);
} else {
viewHolder.read.setVisibility(View.VISIBLE);
viewHolder.read.setText(String.format(Locale.getDefault(), "阅读 %d", views));
viewHolder.read.setText(String.format(Locale.getDefault(), "阅读 %s", NumberUtils.transSimpleCount(views)));
}
NewsUtils.setNewsType(viewHolder.type, newsEntity.getType(), newsEntity.getPriority(), position);
}

View File

@ -17,6 +17,7 @@ import android.widget.TextView;
import com.gh.common.constant.Config;
import com.gh.common.util.CheckLoginUtils;
import com.gh.common.util.ClickUtils;
import com.gh.common.util.DialogUtils;
import com.gh.common.util.EntranceUtils;
import com.gh.common.util.ErrorHelper;
@ -106,7 +107,9 @@ public class MessageDetailFragment extends NormalFragment implements OnCommentCa
String newText = s.toString().substring(0, 140);
mMessageDetailEt.setText(newText);
mMessageDetailEt.setSelection(mMessageDetailEt.getText().length());
Utils.toast(getContext(), "评论不能多于140字");
if (!ClickUtils.isFastDoubleClick(mMessageDetailEt.getId())) {
Utils.toast(getContext(), "评论不能多于140字");
}
}
} else {
mMessageDetailCommentSend.setEnabled(false);

View File

@ -310,6 +310,31 @@ public class NewsDetailAdapter extends BaseRecyclerAdapter<ViewHolder> {
DirectUtils.directToAnswerDetail(mContext, id,
StringUtils.buildString(mEntrance, "+(新闻详情[", mNewsDetailEntity.getTitle(), "])"), "文章链接");
break;
case "communities": // community_article
// ghzhushou://communities/5a32405b2397ab000f688de3/articles/5c99d262c140b321564f04e3
String communityId = "";
String type = "";
String typeId = "";
String[] split = id.split("/");
for (String text : split) {
if (TextUtils.isEmpty(communityId)) {
communityId = text;
continue;
}
if (TextUtils.isEmpty(type)) {
type = text;
continue;
}
if (TextUtils.isEmpty(typeId)) {
typeId = text;
}
}
if ("articles".equals(type)) {
DirectUtils.directToCommunityArticle(
mContext, typeId, communityId,
StringUtils.buildString(mEntrance, "+(新闻详情[", mNewsDetailEntity.getTitle(), "])"));
break;
}
default:
DialogUtils.showLowVersionDialog(mContext);
break;

View File

@ -25,7 +25,7 @@ class FollowersOrFansAdapter(context: Context, val mViewModel: FollowersOrFansVi
}
override fun areContentsTheSame(oldItem: FollowersOrFansEntity?, newItem: FollowersOrFansEntity?): Boolean {
return oldItem?.me?.isFollower == newItem?.me?.isFollower
return oldItem == newItem
}
override fun getItemViewType(position: Int): Int {
@ -60,9 +60,9 @@ class FollowersOrFansAdapter(context: Context, val mViewModel: FollowersOrFansVi
setTextColor(ContextCompat.getColor(mContext, R.color.button_gray))
setBackgroundResource(R.drawable.button_border_gray)
} else if (entity?.me?.isFollower!!) {
setText(R.string.cancel_concern)
setTextColor(ContextCompat.getColor(mContext, R.color.theme))
setBackgroundResource(R.drawable.button_normal_border)
setText(R.string.concerned)
setTextColor(ContextCompat.getColor(mContext, R.color.hint))
setBackgroundResource(R.drawable.questions_detail_tag_bg)
} else {
setText(R.string.concern)
setTextColor(Color.WHITE)

View File

@ -10,7 +10,9 @@ import android.widget.TextView
import com.gh.common.constant.ItemViewType
import com.gh.common.util.DialogUtils
import com.gh.common.util.NewsUtils
import com.gh.common.util.NumberUtils
import com.gh.common.util.ifLogin
import com.gh.gamecenter.NewsDetailActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.UserInfoActivity
import com.gh.gamecenter.ViewImageActivity
@ -84,9 +86,14 @@ class PersonalHomeAdapter(context: Context,
holder.binding.run {
entity = personalData
unreadEntity = mUnreadEntity
if (personalData?.auth != null) {
userAuthCommand.text = personalData?.auth?.text
userAuthCommand.setTextColor(Color.parseColor("#" + personalData?.auth?.color))
personalData?.auth?.let {
userAuthCommand.text = it.text
userAuthCommand.setTextColor(Color.parseColor("#" + it.color))
it.articleId?.let {
userAuthCommand.setOnClickListener {
mContext.startActivity(NewsDetailActivity.getIntentById(mContext, personalData?.auth?.articleId, "$mEntrance+(个人主页)"))
}
}
}
executePendingBindings()
if (mListViewModel.userId == UserManager.getInstance().userId) {
@ -108,9 +115,9 @@ class PersonalHomeAdapter(context: Context,
historiesTitle.text = "Ta的动态"
userConcernOrEdit.run {
if (personalData?.me?.isFollower!!) {
setText(R.string.cancel_concern)
setTextColor(ContextCompat.getColor(mContext, R.color.theme))
setBackgroundResource(R.drawable.button_normal_border)
setText(R.string.concerned)
setTextColor(ContextCompat.getColor(mContext, R.color.hint))
setBackgroundResource(R.drawable.questions_detail_tag_bg)
} else {
setText(R.string.concern)
setTextColor(Color.WHITE)
@ -121,9 +128,8 @@ class PersonalHomeAdapter(context: Context,
userIcon.setOnClickListener {
val list = ArrayList<String>()
list.add(personalData?.icon!!)
mContext.startActivity(ViewImageActivity.getViewImageIntent(mContext, list, 0, "个人主页"))
list.add(personalData?.icon ?: "")
mContext.startActivity(ViewImageActivity.getViewImageIntent(mContext, list, 0, "$mEntrance+(个人主页)"))
}
userFollowerContainer.setOnClickListener {
mContext.startActivity(FollowersActivity.getIntent(mContext, mListViewModel.userId, "$mEntrance+(个人主页)"))
@ -141,7 +147,7 @@ class PersonalHomeAdapter(context: Context,
mContext.startActivity(MyArticleActivity.getIntent(mContext, mListViewModel.userId, "$mEntrance+(个人主页)"))
}
userVoteContainer.setOnClickListener {
Utils.toast(mContext, "共获得 " + entity?.count?.vote + " 赞同")
Utils.toast(mContext, "共获得 " + NumberUtils.transSimpleCount(entity?.count?.vote!!) + " 赞同")
}
userConcernOrEdit.setOnClickListener {
mContext.ifLogin("个人主页-关注-[关注]") {
@ -171,7 +177,7 @@ class PersonalHomeAdapter(context: Context,
endDesc.text = entity?.community?.name
executePendingBindings()
val command = getUserCommand(historyEntity.type, historyEntity.time)
userCommand.text = if (!command.isEmpty()) command else personalData?.name + ""
userCommand.text = if (!command.isEmpty()) command else personalData?.name + ""
questionTitle.setOnClickListener {
if ("community_article" == historyEntity.type || "community_article_vote" == historyEntity.type) {
@ -207,9 +213,9 @@ class PersonalHomeAdapter(context: Context,
mListViewModel.followingCommand(!personalData?.me?.isFollower!!) {
if (it) { // 关注成功
personalData?.me?.isFollower = true
userConcernOrEdit.setText(R.string.cancel_concern)
userConcernOrEdit.setBackgroundResource(R.drawable.button_normal_border)
userConcernOrEdit.setTextColor(ContextCompat.getColor(mContext, R.color.theme))
userConcernOrEdit.setText(R.string.concerned)
userConcernOrEdit.setTextColor(ContextCompat.getColor(mContext, R.color.hint))
userConcernOrEdit.setBackgroundResource(R.drawable.questions_detail_tag_bg)
} else { // 取消关注成功
personalData?.me?.isFollower = false
userConcernOrEdit.setText(R.string.concern)
@ -245,6 +251,7 @@ class PersonalHomeAdapter(context: Context,
else -> ""
}
}
fun getUserCommand(type: String): String {
return when (type) {
"answer" -> "发布了回答"

View File

@ -1,11 +1,13 @@
package com.gh.gamecenter.qa
import android.annotation.SuppressLint
import android.app.Activity
import android.app.Dialog
import android.arch.lifecycle.Observer
import android.arch.lifecycle.ViewModelProviders
import android.content.Intent
import android.content.SharedPreferences
import android.os.Build
import android.os.Bundle
import android.preference.PreferenceManager
import android.support.v4.app.Fragment
@ -22,11 +24,11 @@ import butterknife.OnClick
import com.gh.base.adapter.FragmentAdapter
import com.gh.base.fragment.BaseFragment
import com.gh.base.onDoubleTapListener
import com.gh.common.util.CommunityHelper
import com.gh.common.util.MtaHelper
import com.gh.common.util.SPUtils
import com.gh.gamecenter.MainActivity
import com.gh.common.util.addOnPageChangeListener
import com.gh.common.util.ifLogin
import com.gh.gamecenter.R
import com.gh.gamecenter.entity.ResultEntity
import com.gh.gamecenter.eventbus.EBReuse
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.personal.PersonalFragment
@ -34,6 +36,7 @@ import com.gh.gamecenter.qa.column.AskColumnFragment
import com.gh.gamecenter.qa.column.AskColumnViewModel
import com.gh.gamecenter.qa.follow.AskFollowFragment
import com.gh.gamecenter.qa.newest.AskQuestionsNewFragment
import com.gh.gamecenter.qa.questions.edit.QuestionEditActivity
import com.gh.gamecenter.qa.recommends.AskRecommendWrapperFragment
import com.gh.gamecenter.qa.search.AskSearchActivity
import com.gh.gamecenter.qa.select.CommunitiesSelectActivity
@ -53,20 +56,17 @@ class AskFragment : BaseFragment<Any>() {
const val INDEX_QUESTIONS = 3 // communities
const val COMMUNITIES_SELECT_REQUEST = 103
const val SP_KEY_CLICKED_SELECT_GAME = "has_clicked_select_game"
const val EB_SELECT_KEY = "EB_SELECT_KEY"
const val EB_RETRY_PAGE = "EB_RETRY_PAGE"
const val EB_HIDE_FOLLOW_HINT = "EB_HIDE_FOLLOW_HINT"
const val SCROLL_RECOMMEND_TO_TOP = "SCROLL_RECOMMEND_TO_TOP"
const val SP_KEY_CLICKED_SELECT_GAME = "has_clicked_select_game"
}
@BindView(R.id.ask_selectgame)
lateinit var mAskSelectgame: ImageView
@BindView(R.id.ask_gamename)
lateinit var mAskGamename: TextView
@BindView(R.id.ask_select_community)
lateinit var mAskSelectCommunity: ImageView
@BindView(R.id.ask_community_name)
lateinit var mAskCommunityName: TextView
@BindView(R.id.ask_search)
lateinit var mAskSearch: ImageView
@BindView(R.id.ask_follow)
@ -91,14 +91,10 @@ class AskFragment : BaseFragment<Any>() {
lateinit var mCommunitiesSelectLayout: View
@BindView(R.id.ask_column_line)
lateinit var mColumnLine: View
@BindView(R.id.reuse_nodata_skip)
lateinit var mNoAvailableCommunityHint: View
@BindView(R.id.follow_hint)
lateinit var mFollowHint: View
@BindView(R.id.reuse_nodata_skip_tv_hint)
lateinit var mNoAvailableCommunityTv: TextView
@BindView(R.id.reuse_nodata_skip_tv_btn)
lateinit var mNoAvailableCommunityBtn: TextView
@BindView(R.id.ask_put_questions)
lateinit var mPutQuestions: View
private lateinit var mRecommendsFragment: AskRecommendWrapperFragment
@ -136,16 +132,46 @@ class AskFragment : BaseFragment<Any>() {
}
})
mViewModel.communityStatus.observe(this, Observer { status ->
status?.let {
val channel = HaloApp.getInstance().channel
// MARK:只要是测试社区都忽略隐藏判断
if (TextUtils.isEmpty(UserManager.getInstance().community.id)
|| (!status.isActive && !channel.contains("TEST"))) {
showCommunitySelectFragment()
} else {
mAskCommunityName.text = UserManager.getInstance().community.name
showAvailableInfo()
initViewPager()
setTabBarPosition(INDEX_HOT)
if (mOpenedFragment != null) hideCommunitySelectFragmentAndShowCommunityWithHint()
val result = status.data
if (result != null) {
val fragments = childFragmentManager.fragments
for (fragment in fragments) {
fragment.onActivityResult(result.requestCode, result.resultCode, result.data)
}
}
}
}
})
mColumnViewModel.tagGroupsObservable.observe(this, Observer { it ->
if ((it == null || it.isEmpty()) && mAskColumn.visibility == View.VISIBLE) {
mAskColumn.visibility = View.GONE
mColumnLine.visibility = View.GONE
if (mAskColumn.isChecked) setTabbarPosition(INDEX_HOT)
if (mAskColumn.isChecked) setTabBarPosition(INDEX_HOT)
} else if (it != null && !it.isEmpty() && mAskColumn.visibility == View.GONE) {
mAskColumn.visibility = View.VISIBLE
mColumnLine.visibility = View.VISIBLE
}
})
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mPutQuestions.elevation = 10F
}
}
override fun onResume() {
@ -162,78 +188,32 @@ class AskFragment : BaseFragment<Any>() {
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == COMMUNITIES_SELECT_REQUEST && resultCode == Activity.RESULT_OK) {
val isThisCommunityAvailable = CommunityHelper.isCommunityAvailable(UserManager.getInstance().community.id)
SPUtils.setBoolean(UserManager.getInstance().community.id, isThisCommunityAvailable)
if (isThisCommunityAvailable) {
hideCommunitySelectFragmentAndShowCommunityWithHint()
showAvailableInfo()
val fragments = childFragmentManager.fragments
for (fragment in fragments) {
fragment.onActivityResult(requestCode, resultCode, data)
}
} else {
UserManager.getInstance().community.name = "光环问答"
// 在 SP 中将当前社区 ID 设为不可用(隐藏),方便关闭回来还是显示当前社区为隐藏社区
hideCommunitySelectFragmentAndShowCommunityWithHint()
showUnavailableInfo()
}
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
if (MainActivity.isNewFirstLaunch && !MainActivity.openCommunityWithDefaultIdForTheFirsTime
|| UserManager.getInstance().community == null
|| TextUtils.isEmpty(UserManager.getInstance().community.id)) {
showCommunitySelectFragment()
} else {
mLoading.visibility = View.GONE
// 从 SP 获取判断此社区是否可用
val isThisCommunityAvailable = SPUtils.getBoolean(UserManager.getInstance().community.id)
if (isThisCommunityAvailable) {
mAskTabBar.visibility = View.VISIBLE
mAskGamename.text = UserManager.getInstance().community.name
initViewPager()
setTabbarPosition(INDEX_HOT)
} else {
showUnavailableInfo()
}
mViewModel.checkCommunity(ResultEntity(requestCode, resultCode, data))
}
}
// 社区没有被隐藏,正常显示社区信息
private fun showAvailableInfo() {
mAskGamename.text = UserManager.getInstance().community.name
mAskCommunityName.text = UserManager.getInstance().community.name
mAskSearch.visibility = View.VISIBLE
mAskTabBar.visibility = View.VISIBLE
mNoAvailableCommunityHint.visibility = View.GONE
mAskViewpager.visibility = View.VISIBLE
mAskSelectCommunity.visibility = View.VISIBLE
mCommunitiesSelectLayout.visibility = View.GONE
mLoading.visibility = View.GONE
}
// 社区被隐藏,显示缺省信息
private fun showUnavailableInfo() {
mAskGamename.text = "光环问答"
mAskTabBar.visibility = View.GONE
mAskViewpager.visibility = View.INVISIBLE
mAskSearch.visibility = View.INVISIBLE
mNoAvailableCommunityTv.text = "未发现内容"
mNoAvailableCommunityBtn.text = "[切换游戏]"
mNoAvailableCommunityBtn.setOnClickListener { mAskSelectgame.performClick() }
mNoAvailableCommunityHint.visibility = View.VISIBLE
}
@OnClick(R.id.ask_selectgame,
@OnClick(R.id.ask_select_community,
R.id.ask_search,
R.id.ask_hot,
R.id.ask_follow,
R.id.ask_questions,
R.id.ask_column,
R.id.reuse_no_connection)
R.id.reuse_no_connection,
R.id.ask_put_questions)
fun onViewClicked(view: View) {
when (view.id) {
R.id.ask_selectgame -> {
R.id.ask_select_community -> {
if (!mHasClickedSelectGame) {
mHasClickedSelectGame = true
sp.edit().putBoolean(SP_KEY_CLICKED_SELECT_GAME, mHasClickedSelectGame).apply()
@ -251,7 +231,7 @@ class AskFragment : BaseFragment<Any>() {
startActivity(AskSearchActivity.getIntent(context, "(首页-问答)"))
}
R.id.ask_follow -> {
setTabbarPosition(INDEX_FOLLOW)
setTabBarPosition(INDEX_FOLLOW)
// 关注 tab 存在未读红点,刷新一下
val isRefreshing = mAskFollowFragment.load()
if (mFollowHint.visibility == View.VISIBLE &&
@ -261,24 +241,38 @@ class AskFragment : BaseFragment<Any>() {
MtaHelper.onEvent("问答页面", UserManager.getInstance().community.name, "关注Tab")
}
R.id.ask_hot -> {
setTabbarPosition(INDEX_HOT)
setTabBarPosition(INDEX_HOT)
MtaHelper.onEvent("问答页面", UserManager.getInstance().community.name, "推荐Tab")
}
R.id.ask_questions -> {
setTabbarPosition(INDEX_QUESTIONS)
setTabBarPosition(INDEX_QUESTIONS)
MtaHelper.onEvent("问答页面", UserManager.getInstance().community.name, "问题Tab")
}
R.id.ask_column -> {
setTabbarPosition(INDEX_COLUMN)
setTabBarPosition(INDEX_COLUMN)
MtaHelper.onEvent("问答页面", UserManager.getInstance().community.name, "专栏Tab")
}
R.id.reuse_no_connection -> {
mNoConn.visibility = View.GONE
mLoading.visibility = View.VISIBLE
}
R.id.ask_put_questions -> {
val positionType = if (mAskViewpager.currentItem == INDEX_FOLLOW) {
"关注-提问"
} else if (mAskViewpager.currentItem == INDEX_COLUMN) {
"推荐-提问"
} else {
"问题-提问"
}
MtaHelper.onEvent("问答页面", "问答页面", positionType)
context?.ifLogin("(首页-问答)", action = {
startActivity(QuestionEditActivity.getIntent(context!!))
})
}
}
}
@SuppressLint("ClickableViewAccessibility")
private fun initViewPager() {
val fragmentList = ArrayList<Fragment>()
mRecommendsFragment = AskRecommendWrapperFragment()
@ -290,7 +284,15 @@ class AskFragment : BaseFragment<Any>() {
mAskViewpager.setScrollable(false)
mAskViewpager.offscreenPageLimit = fragmentList.size
mAskGamename.setOnTouchListener(object : onDoubleTapListener(context) {
mAskViewpager.addOnPageChangeListener(onSelected = {
mPutQuestions.visibility = if (fragmentList[it] is AskColumnFragment) {
View.GONE
} else {
View.VISIBLE
}
})
mAskCommunityName.setOnTouchListener(object : onDoubleTapListener(context) {
override fun onDoubleTap() {
when (mAskViewpager.currentItem) {
INDEX_FOLLOW -> {
@ -303,7 +305,7 @@ class AskFragment : BaseFragment<Any>() {
})
}
private fun setTabbarPosition(index: Int) {
private fun setTabBarPosition(index: Int) {
when (index) {
INDEX_FOLLOW -> {
mAskFollow.isChecked = true
@ -361,9 +363,10 @@ class AskFragment : BaseFragment<Any>() {
}
private fun showCommunitySelectFragment() {
mAskSelectgame.visibility = View.INVISIBLE
mPutQuestions.visibility = View.GONE
mAskSelectCommunity.visibility = View.INVISIBLE
mAskSearch.visibility = View.INVISIBLE
mAskGamename.text = "选择游戏"
mAskCommunityName.text = "选择游戏"
mAskTabBar.visibility = View.GONE
mLoading.visibility = View.GONE
mCommunitiesSelectLayout.visibility = View.VISIBLE
@ -372,18 +375,9 @@ class AskFragment : BaseFragment<Any>() {
}
private fun hideCommunitySelectFragmentAndShowCommunityWithHint() {
mAskSelectgame.visibility = View.VISIBLE
mAskSearch.visibility = View.VISIBLE
mCommunitiesSelectLayout.visibility = View.GONE
mAskTabBar.visibility = View.VISIBLE
mAskGamename.text = UserManager.getInstance().community.name
initViewPager()
setTabbarPosition(INDEX_HOT)
if (mOpenedFragment != null) {
childFragmentManager.beginTransaction().remove(mOpenedFragment).commitNowAllowingStateLoss()
}
mOpenedFragment = null
childFragmentManager.beginTransaction().remove(mOpenedFragment).commitNowAllowingStateLoss()
showHintDialog()
mOpenedFragment = null
}
private fun showHintDialog() {
@ -404,12 +398,12 @@ class AskFragment : BaseFragment<Any>() {
val view = viewDialog.findViewById<View>(R.id.communities_select_hint)
val cancel = viewDialog.findViewById<View>(R.id.communities_select_cancel)
val title = viewDialog.findViewById<View>(R.id.communities_select_title)
view.setOnClickListener { _ ->
view.setOnClickListener {
dialog.dismiss()
startActivityForResult(CommunitiesSelectActivity.getIntent(context), COMMUNITIES_SELECT_REQUEST)
}
cancel.setOnClickListener { _ -> dialog.dismiss() }
title.setOnClickListener { _ -> dialog.dismiss() }
cancel.setOnClickListener { dialog.dismiss() }
title.setOnClickListener { dialog.dismiss() }
val params = ViewGroup.LayoutParams(resources.displayMetrics.widthPixels, ViewGroup.LayoutParams.WRAP_CONTENT)
dialog.setContentView(viewDialog, params)
}

View File

@ -3,9 +3,14 @@ package com.gh.gamecenter.qa
import android.app.Application
import android.arch.lifecycle.AndroidViewModel
import android.arch.lifecycle.MutableLiveData
import android.text.TextUtils
import com.gh.gamecenter.entity.ResultEntity
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.qa.entity.AskGameSelectEntity
import com.gh.gamecenter.qa.entity.CommunityStatusEntity
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import retrofit2.HttpException
@ -17,6 +22,11 @@ class AskViewModel(application: Application) : AndroidViewModel(application) {
private lateinit var mTimer: Timer
var unreadCommunity = MutableLiveData<Boolean>()
var communityStatus = MutableLiveData<CommunityStatusEntity>()
init {
checkCommunity(null)
}
fun checkUnreadFollowTimeline() {
cancelTimer()
@ -44,6 +54,32 @@ class AskViewModel(application: Application) : AndroidViewModel(application) {
}
}
fun checkCommunity(data: ResultEntity?) {
val id = UserManager.getInstance().community.id
if (TextUtils.isEmpty(id)) {
communityStatus.postValue(CommunityStatusEntity(false, data))
return
}
RetrofitManager.getInstance(getApplication())
.api.getCommunityDesc(id)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<AskGameSelectEntity>() {
override fun onResponse(response: AskGameSelectEntity?) {
communityStatus.postValue(CommunityStatusEntity(true, data))
}
override fun onFailure(e: HttpException?) {
if (e?.code() == 404) {
communityStatus.postValue(CommunityStatusEntity(false, data))
} else {
communityStatus.postValue(CommunityStatusEntity(true, data))
}
}
})
}
private fun cancelTimer() {
if (::mTimer.isInitialized) {
mTimer.cancel()

File diff suppressed because it is too large Load Diff

View File

@ -6,8 +6,11 @@ import android.arch.lifecycle.LiveData
import android.arch.lifecycle.MutableLiveData
import android.text.Html
import com.gh.common.util.DataUtils
import com.gh.common.util.LogUtils
import com.gh.common.util.MtaHelper
import com.gh.common.util.StringUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.entity.SpecialColumn
import com.gh.gamecenter.entity.VoteEntity
import com.gh.gamecenter.qa.entity.AnswerDetailEntity
import com.gh.gamecenter.retrofit.Response
@ -16,9 +19,12 @@ import com.gh.gamecenter.user.ApiResponse
import com.lightgame.utils.Utils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.RequestBody
import okhttp3.ResponseBody
import org.json.JSONObject
import retrofit2.HttpException
import java.util.*
class AnswerDetailViewModel(application: Application) : AndroidViewModel(application) {
@ -29,6 +35,7 @@ class AnswerDetailViewModel(application: Application) : AndroidViewModel(applica
val highlight = MutableLiveData<Boolean>()
val hide = MutableLiveData<Boolean>()
val fold = MutableLiveData<Boolean>()
val commentable = MutableLiveData<Boolean>()
val answerLiveData: LiveData<ApiResponse<AnswerDetailEntity>>
get() = mAnswerLiveData
@ -119,6 +126,27 @@ class AnswerDetailViewModel(application: Application) : AndroidViewModel(applica
})
}
fun toggleComment(answerId: String, isCommentable: Boolean) {
val params = HashMap<String, Boolean>()
params["commentable"] = isCommentable
val body = RequestBody.create(MediaType.parse("application/json"),
JSONObject(params).toString())
RetrofitManager.getInstance(getApplication())
.api
.postAnswerCommentable(answerId, body)
.subscribeOn(Schedulers.io())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
commentable.postValue(isCommentable)
}
override fun onFailure(e: HttpException?) {
Utils.toast(getApplication(), e?.message())
}
})
}
fun doHighlightThisAnswer(answerId: String) {
RetrofitManager.getInstance(getApplication()).api
.highlightAnswer(answerId)
@ -197,4 +225,37 @@ class AnswerDetailViewModel(application: Application) : AndroidViewModel(applica
})
}
fun trackReadEvent(answerId: String,
answerDetailEntity: AnswerDetailEntity,
elapsedTime: Int,
entrance: String,
path: String,
specialColumn: SpecialColumn?) {
MtaHelper.onEventWithTime(
"答案阅读量_按社区",
elapsedTime,
answerDetailEntity.community.name,
StringUtils.combineTwoString(answerDetailEntity.content, answerId))
MtaHelper.onEventWithTime(
"答案阅读量_按位置",
elapsedTime,
path,
StringUtils.combineTwoString(answerDetailEntity.content, answerId))
MtaHelper.onEventWithTime(
"答案阅读量_社区加位置",
elapsedTime,
answerDetailEntity.community.name,
path)
LogUtils.uploadAnswerReadTime(entrance,
elapsedTime,
answerId,
answerDetailEntity.question,
answerDetailEntity.community.id,
answerDetailEntity.community.name,
specialColumn)
}
}

View File

@ -1,64 +0,0 @@
package com.gh.gamecenter.qa.answer.edit;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import com.gh.common.util.EntranceUtils;
import com.gh.gamecenter.NormalActivity;
/**
* Created by khy on 10/04/18.
*/
public class AnswerEditActivity extends NormalActivity {
/**
* 撰写回答
*/
public static Intent getIntent(Context context, String questionId, String questionTitle, boolean showInNewPage, String communityName) {
Bundle bundle = new Bundle();
bundle.putString(EntranceUtils.KEY_QUESTIONS_ID, questionId);
bundle.putString(EntranceUtils.KEY_QUESTIONS_TITLE, questionTitle);
bundle.putBoolean(EntranceUtils.KEY_ANSWER_OPEN_IN_NEW_PAGE, showInNewPage);
bundle.putString(EntranceUtils.KEY_COMMUNITY_NAME, communityName);
return getTargetIntent(context, AnswerEditActivity.class, AnswerEditFragment.class, bundle);
}
/**
* 撰写回答(存在回答草稿)
*/
public static Intent getIntent(Context context, String questionId, String questionTitle, String draftId, boolean showInNewPage, String communityName) {
Bundle bundle = new Bundle();
bundle.putString(EntranceUtils.KEY_QUESTIONS_ID, questionId);
bundle.putString(EntranceUtils.KEY_QUESTIONS_TITLE, questionTitle);
bundle.putBoolean(EntranceUtils.KEY_ANSWER_OPEN_IN_NEW_PAGE, showInNewPage);
bundle.putString(EntranceUtils.KEY_DRAFT_ID, draftId);
bundle.putString(EntranceUtils.KEY_COMMUNITY_NAME, communityName);
return getTargetIntent(context, AnswerEditActivity.class, AnswerEditFragment.class, bundle);
}
/**
* 撰写回答
*/
public static Intent getIntent(Context context, String questionId, String questionTitle, String communityName) {
Bundle bundle = new Bundle();
bundle.putString(EntranceUtils.KEY_QUESTIONS_ID, questionId);
bundle.putString(EntranceUtils.KEY_QUESTIONS_TITLE, questionTitle);
bundle.putString(EntranceUtils.KEY_COMMUNITY_NAME, communityName);
return getTargetIntent(context, AnswerEditActivity.class, AnswerEditFragment.class, bundle);
}
/**
* 修改回答
*/
public static Intent getIntent(Context context, String answerId, String questionTitle, String content, String communityName) {
Bundle bundle = new Bundle();
bundle.putString(EntranceUtils.KEY_ANSWER_ID, answerId);
bundle.putString(EntranceUtils.KEY_QUESTIONS_TITLE, questionTitle);
bundle.putString(EntranceUtils.KEY_ANSWER_CONTENT, content);
bundle.putString(EntranceUtils.KEY_COMMUNITY_NAME, communityName);
return getTargetIntent(context, AnswerEditActivity.class, AnswerEditFragment.class, bundle);
}
}

View File

@ -0,0 +1,429 @@
package com.gh.gamecenter.qa.answer.edit
import android.app.Activity
import android.app.Dialog
import android.arch.lifecycle.Observer
import android.arch.lifecycle.ViewModelProviders
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.Message
import android.text.TextUtils
import android.view.MenuItem
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.ImageView
import android.widget.TextView
import butterknife.OnClick
import com.gh.base.BaseRichEditorActivity
import com.gh.base.fragment.WaitingDialogFragment
import com.gh.common.util.*
import com.gh.gamecenter.R
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.mvvm.Status
import com.gh.gamecenter.qa.answer.detail.AnswerDetailActivity
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import com.zhihu.matisse.Matisse
import com.zhihu.matisse.MimeType
import kotterknife.bindView
import org.json.JSONObject
/**
* Created by khy on 10/04/18.
*/
class AnswerEditActivity : BaseRichEditorActivity() {
companion object {
const val ANSWER_DRAFT_CHANGE_TAG = "ANSWER_DRAFT_CHANGE_TAG"
const val FILE_HOST = "file:///"
const val SAVE_DRAFTS = 110
const val REQUEST_CODE_IMAGE = 111
const val SAVE_DRAFTS_INTERVAL_TIME = 15000
const val SAVE_DRAFTS_TOAST_COUNT = 3
const val MIN_ANSWER_TEXT_LENGTH = 6
const val MAX_ANSWER_TEXT_LENGTH = 10000
/**
* 撰写回答
*/
fun getIntent(context: Context, questionId: String?, questionTitle: String?, showInNewPage: Boolean?, communityName: String?): Intent {
val intent = Intent(context, AnswerEditActivity::class.java)
intent.putExtra(EntranceUtils.KEY_QUESTIONS_ID, questionId)
intent.putExtra(EntranceUtils.KEY_QUESTIONS_TITLE, questionTitle)
intent.putExtra(EntranceUtils.KEY_ANSWER_OPEN_IN_NEW_PAGE, showInNewPage)
intent.putExtra(EntranceUtils.KEY_COMMUNITY_NAME, communityName)
return intent
}
/**
* 撰写回答(存在回答草稿)
*/
fun getIntent(context: Context, questionId: String?, questionTitle: String?, draftId: String?, showInNewPage: Boolean?, communityName: String?): Intent {
val intent = Intent(context, AnswerEditActivity::class.java)
intent.putExtra(EntranceUtils.KEY_QUESTIONS_ID, questionId)
intent.putExtra(EntranceUtils.KEY_QUESTIONS_TITLE, questionTitle)
intent.putExtra(EntranceUtils.KEY_ANSWER_OPEN_IN_NEW_PAGE, showInNewPage)
intent.putExtra(EntranceUtils.KEY_DRAFT_ID, draftId)
intent.putExtra(EntranceUtils.KEY_COMMUNITY_NAME, communityName)
return intent
}
/**
* 撰写回答
*/
fun getIntent(context: Context, questionId: String?, questionTitle: String?, communityName: String?): Intent {
val intent = Intent(context, AnswerEditActivity::class.java)
intent.putExtra(EntranceUtils.KEY_QUESTIONS_ID, questionId)
intent.putExtra(EntranceUtils.KEY_QUESTIONS_TITLE, questionTitle)
intent.putExtra(EntranceUtils.KEY_COMMUNITY_NAME, communityName)
return intent
}
/**
* 修改回答
*/
fun getIntent(context: Context, answerId: String?, questionTitle: String?, content: String?, communityName: String?): Intent {
val intent = Intent(context, AnswerEditActivity::class.java)
intent.putExtra(EntranceUtils.KEY_ANSWER_ID, answerId)
intent.putExtra(EntranceUtils.KEY_QUESTIONS_TITLE, questionTitle)
intent.putExtra(EntranceUtils.KEY_ANSWER_CONTENT, content)
intent.putExtra(EntranceUtils.KEY_COMMUNITY_NAME, communityName)
return intent
}
}
private val mTitle by bindView<TextView>(R.id.answer_edit_title)
private val mImgIcon by bindView<ImageView>(R.id.editor_image)
private val mEditPlaceholder by bindView<View>(R.id.answer_placeholder)
private var mProcessingDialog: WaitingDialogFragment? = null
private var mUploadImageCancelDialog: Dialog? = null
private var mQuestionsTitle: String? = null
private var mCommunityName: String? = null
private var mOpenAnswerInNewPage: Boolean = false
private var mAgreePostPic: Boolean = false
private var mViewModel: AnswerEditViewModel? = null
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
if (msg.what == 1) {
readySaveAnswerDrafts(false)
mBaseHandler.sendEmptyMessageDelayed(1, SAVE_DRAFTS_INTERVAL_TIME.toLong())
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE_IMAGE && resultCode == Activity.RESULT_OK) {
if (data != null) mViewModel?.postImg(data)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setToolbarMenu(R.menu.menu_answer_post)
mQuestionsTitle = intent?.getStringExtra(EntranceUtils.KEY_QUESTIONS_TITLE)
mCommunityName = intent?.getStringExtra(EntranceUtils.KEY_COMMUNITY_NAME)
mOpenAnswerInNewPage = intent?.getBooleanExtra(EntranceUtils.KEY_ANSWER_OPEN_IN_NEW_PAGE, false)!!
val factory = AnswerEditViewModel.Factory(
HaloApp.getInstance().application,
intent?.getStringExtra(EntranceUtils.KEY_ANSWER_ID),
intent?.getStringExtra(EntranceUtils.KEY_ANSWER_CONTENT),
intent?.getStringExtra(EntranceUtils.KEY_DRAFT_ID),
intent?.getStringExtra(EntranceUtils.KEY_QUESTIONS_ID))
mViewModel = ViewModelProviders.of(this, factory).get(AnswerEditViewModel::class.java)
addObserver()
if (TextUtils.isEmpty(mViewModel?.answerId)) {
mBaseHandler.sendEmptyMessageDelayed(1, SAVE_DRAFTS_INTERVAL_TIME.toLong()) // 启动自动保持
}
mTitle.text = mQuestionsTitle
mRichEditor.setPadding(20, 15, 20, 15)
mRichEditor.setOnTextChangeListener { t ->
if (t.contains("<img src") || !TextUtils.isEmpty(mRichEditor.text)) {
mEditPlaceholder.visibility = View.GONE
} else {
mEditPlaceholder.visibility = View.VISIBLE
}
}
mRichEditor.setOnInitialLoadListener { isReady ->
if (isReady) {
mRichEditor.scrollTo(0, 10000000)
try {
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(mRichEditor, InputMethodManager.SHOW_IMPLICIT)
} catch (e: Exception) {
e.printStackTrace()
}
mRichEditor.postDelayed({ mRichEditor.focusEditor() }, 800)
}
}
if (!TextUtils.isEmpty(mViewModel?.answerId)) {
setNavigationTitle(getString(R.string.answer_patch_title))
mViewModel?.cacheAnswerContent = mViewModel?.answerContent
mRichEditor.setHtml(mViewModel?.answerContent, false)
} else {
setNavigationTitle(getString(R.string.answer_edit_title))
mViewModel?.getUserAnswerDrafts()
}
}
override fun getLayoutId(): Int {
return R.layout.fragment_answer_edit
}
override fun onMenuItemClick(item: MenuItem?): Boolean {
if (item?.itemId == R.id.menu_answer_post && !ClickUtils.isFastDoubleClick(R.id.menu_answer_post, 5000)) {
readyPost()
}
return super.onMenuItemClick(item)
}
private fun addObserver() {
mViewModel?.postLiveData?.observe(this, Observer {
if (it?.status == Status.SUCCESS) {
MtaHelper.onEvent("发表答案", "提交成功", mCommunityName)
toast("发布成功")
var answerId: String? = null
try {
answerId = JSONObject(it.data?.string()).getString("_id")
} catch (e: Exception) {
e.printStackTrace()
}
val data = Intent()
data.putExtra(EntranceUtils.KEY_ANSWER_CONTENT, getReplaceNetImageContent())
data.putExtra(EntranceUtils.KEY_ANSWER_ID, answerId)
setResult(Activity.RESULT_OK, data)
if (mOpenAnswerInNewPage) {
val intent = AnswerDetailActivity
.getIntent(this, answerId, mEntrance, "编辑答案")
startActivity(intent)
}
finish()
} else if (it?.status == Status.ERROR) {
var errorString: String? = null
val e = it.exception
if (e != null && e.code() == 403) {
try {
errorString = e.response().errorBody()!!.string()
val string = JSONObject(errorString)
val code = string.getInt("code")
if (code == 403037) {
if (TextUtils.isEmpty(mViewModel?.draftId)) {
DialogUtils.showAlertDialog(this, "发布失败"
, "问题已被删除,无法发布回答", "好吧", "", {
finish()
}, null)
} else {
DialogUtils.showAlertDialog(this, "发布失败"
, "问题已被删除,需要删除草稿吗?", "删除草稿"
, "暂不", { mViewModel?.deleteAnswerDraft() }, {
finish()
})
}
return@Observer
} else {
ErrorHelper.handleError(this, errorString, false)
return@Observer
}
} catch (e1: Exception) {
e1.printStackTrace()
}
}
ErrorHelper.handleError(this, errorString, false)
}
})
mViewModel?.processDialog?.observe(this, Observer {
if (it?.isShow!!) {
if (mProcessingDialog?.dialog?.isShowing == true) {
mProcessingDialog?.uploadWaitingHint(it.msg)
} else {
mProcessingDialog = WaitingDialogFragment.newInstance(it.msg, false)
mProcessingDialog?.show(supportFragmentManager, null) {
if (mViewModel?.uploadImageSubscription != null && !mViewModel?.uploadImageSubscription!!.isDisposed) {
mUploadImageCancelDialog = DialogUtils.showAlertDialog(this, "提示"
, "图片正在上传中,确定取消吗?"
, "确定", "取消", {
mViewModel?.uploadImageSubscription!!.dispose()
mUploadImageCancelDialog?.dismiss()
mProcessingDialog?.dismiss()
}, null)
}
}
}
} else {
mUploadImageCancelDialog?.dismiss()
mProcessingDialog?.dismiss()
}
})
mViewModel?.postImageLiveData?.observe(this, Observer {
if (it?.status == Status.SUCCESS) {
val imageUrl = it.data!!
for (sourceImage in imageUrl.keys) {
mViewModel?.mapImages?.set(TextUtils.htmlEncode(sourceImage), imageUrl[sourceImage]!!)
mRichEditor.insertImage(FILE_HOST + sourceImage)
}
}
})
mViewModel?.deleteDraftLiveDate?.observe(this, Observer {
if (it == true) {
setResult(Activity.RESULT_OK)
finish()
}
})
mViewModel?.draftsLiveData?.observe(this, Observer {
mRichEditor.setHtml(it, false)
})
mViewModel?.saveDraftsLiveData?.observe(this, Observer {
if (it == null) return@Observer
if (it) {
val data = Intent()
data.putExtra(EntranceUtils.KEY_ANSWER_CONTENT, getReplaceNetImageContent())
setResult(SAVE_DRAFTS, data)
finish()
} else {
showDraftFailureDialog()
}
})
}
private fun readyPost() {
CheckLoginUtils.checkLogin(this, "回答编辑-提交") {
val answerContent = getReplaceNetImageContent()
// filter rule
val answerLength = answerContent.length
if (answerLength < MIN_ANSWER_TEXT_LENGTH) {
toast(R.string.answer_beneath_length_limit)
return@checkLogin
} else if (answerLength > MAX_ANSWER_TEXT_LENGTH) {
DialogUtils.showAlertDialog(this,
getString(R.string.answer_post_failed),
getString(R.string.answer_exceed_length_limit,
MAX_ANSWER_TEXT_LENGTH,
answerLength - MAX_ANSWER_TEXT_LENGTH),
getString(R.string.answer_resume_edit), "", {
// do nothing
}, null)
return@checkLogin
}
Utils.log("answerEditHtml:$answerContent")
mViewModel?.postAnswer(answerContent)
}
}
private fun getReplaceNetImageContent(): String {
var answerContent = mRichEditor.html
for (s in mViewModel?.mapImages?.keys!!) {
val netUrl = mViewModel?.mapImages?.get(s)
if (netUrl != null) {
answerContent = answerContent.replace(FILE_HOST + s, netUrl)
}
}
return answerContent
}
override fun handleBackPressed(): Boolean {
if (TextUtils.isEmpty(UserManager.getInstance().token)) {
return false
} else if (!TextUtils.isEmpty(mViewModel?.answerId)) {
showPatchBackDialog()
return true
} else if (TextUtils.isEmpty(mRichEditor.html) ||
!TextUtils.isEmpty(mViewModel?.cacheAnswerContent)
&& mViewModel?.cacheAnswerContent == mRichEditor.html) {
return false
} else {
readySaveAnswerDrafts(true)
return true
}
}
override fun onDestroy() {
super.onDestroy()
mProcessingDialog?.dismissAllowingStateLoss()
mProcessingDialog == null
}
private fun showDraftFailureDialog() {
DialogUtils.showAlertDialog(this,
"提示",
"确定退出?已撰写的内容将会丢失",
"继续撰写", "退出", null, { finish() })
}
private fun showPatchBackDialog() {
DialogUtils.showCancelAlertDialog(this, "提示", "确定退出修改?已修改的内容将丢失",
"继续写", " 退出", null, { finish() })
}
private fun readySaveAnswerDrafts(isExit: Boolean) {
val editContent = getReplaceNetImageContent()
if (TextUtils.isEmpty(UserManager.getInstance().token)) {
return
} else if (isExit && TextUtils.isEmpty(editContent)) {
finish()
return
} else if (!isExit && TextUtils.isEmpty(editContent)) { // || editContent.equals(mCacheAnswerContent)
return
}
mViewModel?.saveAnswerDrafts(editContent, isExit)
}
@OnClick(R.id.editor_image)
fun onClick(view: View) {
when (view.id) {
R.id.editor_image -> {
MtaHelper.onEvent("发表答案", "上传图片", mCommunityName)
if (!mAgreePostPic && !NetworkUtils.isWifiOr4GOr3GConnected(this)) {
mAgreePostPic = true
DialogUtils.showAlertDialog(this,
"警告",
"当前使用移动网络,上传图片会消耗手机流量",
"我知道了", "", { startMediaStore() }, null)
MtaHelper.onEvent("发表答案", "上传图片-移动网络提示", mCommunityName)
return
}
startMediaStore()
}
}
}
private fun startMediaStore() {
if (mViewModel?.mapImages!!.size >= 50) {
toast(R.string.answer_edit_max_img_hint)
return
}
try {
Matisse.from(this)
.choose(MimeType.ofAll())
.countable(true)
.maxSelectable(10)
.forResult(REQUEST_CODE_IMAGE)
} catch (e: Exception) {
toast(R.string.media_image_hint)
e.printStackTrace()
}
}
}

View File

@ -1,599 +0,0 @@
package com.gh.gamecenter.qa.answer.edit;
import android.app.Activity;
import android.app.Dialog;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Message;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.webkit.JavascriptInterface;
import android.widget.ImageView;
import android.widget.TextView;
import com.gh.base.fragment.WaitingDialogFragment;
import com.gh.common.util.CheckLoginUtils;
import com.gh.common.util.ClickUtils;
import com.gh.common.util.DialogUtils;
import com.gh.common.util.EntranceUtils;
import com.gh.common.util.ErrorHelper;
import com.gh.common.util.ImageUtils;
import com.gh.common.util.MtaHelper;
import com.gh.common.util.NetworkUtils;
import com.gh.common.util.UploadImageUtils;
import com.gh.common.view.RichEditor;
import com.gh.gamecenter.R;
import com.gh.gamecenter.eventbus.EBReuse;
import com.gh.gamecenter.manager.UserManager;
import com.gh.gamecenter.normal.NormalFragment;
import com.gh.gamecenter.qa.answer.detail.AnswerDetailActivity;
import com.gh.gamecenter.retrofit.Response;
import com.gh.gamecenter.retrofit.RetrofitManager;
import com.halo.assistant.HaloApp;
import com.halo.assistant.fragment.user.SelectPortraitFragment;
import com.lightgame.config.CommonDebug;
import com.lightgame.utils.Utils;
import org.greenrobot.eventbus.EventBus;
import org.jetbrains.annotations.NotNull;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import butterknife.BindView;
import butterknife.OnClick;
import io.reactivex.Observable;
import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import okhttp3.internal.http.RealResponseBody;
import retrofit2.HttpException;
/**
* Created by khy on 7/12/17.
*/
public class AnswerEditFragment extends NormalFragment {
@BindView(R.id.answer_edit_title)
TextView mTitle;
@BindView(R.id.answer_edit_content)
RichEditor mEditContent;
@BindView(R.id.answer_edit_img_icon)
ImageView mImgIcon;
@BindView(R.id.answer_placeholder)
View mEditPlaceholder;
public final static int SAVE_DRAFTS = 110;
public static final String ANSWER_DRAFT_CHANGE_TAG = "ANSWER_DRAFT_CHANGE_TAG";
private final static String FILE_HOST = "file:///";
private final static int SAVE_DRAFTS_INTERVAL_TIME = 15000;
private final static int SAVE_DRAFTS_TOAST_COUNT = 3;
private static final int MIN_ANSWER_TEXT_LENGTH = 6;
private static final int MAX_ANSWER_TEXT_LENGTH = 10000;
private boolean mAgreePostPic;
private Map<String, String> mMapImg = new HashMap<>();
private WaitingDialogFragment postDialog;
private Disposable mUploadImageDisposable;
private Dialog mUpdateImageCancelDialog;
private String mAnswerId; // 以mAnswerId为标识如果mAnswerId不为空则是-修改答案(不需要保存草稿) 为空则是-编写答案
private String mAnswerContent;
private String mDraftId;
private String mQuestionsId;
private String mQuestionsTitle;
private String mCommunityName;
private boolean mOpenAnswerInNewPage;
private String mCacheAnswerContent;
private int mPostDraftsCount;
@Override
protected void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 1) {
saveAnswerDrafts(false);
mBaseHandler.sendEmptyMessageDelayed(1, SAVE_DRAFTS_INTERVAL_TIME);
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (data != null && requestCode == SelectPortraitFragment.REQUEST_MEDIA_ICON) {
Uri selectedImage = data.getData();
if (selectedImage == null || getActivity() == null) {
return;
}
String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = getActivity().getContentResolver().query(selectedImage, filePathColumn, null, null, null);
if (cursor == null) {
return;
}
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
cursor.close();
if (new File(picturePath).length() > ImageUtils.getUploadFileMaxSize()) {
long count = ImageUtils.getUploadFileMaxSize() / 1024 / 1024;
Utils.toast(getContext(), getString(R.string.pic_max_hint, count));
return;
}
postImg(picturePath);
Utils.log("picturePath = " + picturePath);
}
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
initMenu(R.menu.menu_answer_post);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle arguments = getArguments();
if (arguments != null) {
mAnswerId = arguments.getString(EntranceUtils.KEY_ANSWER_ID);
mAnswerContent = arguments.getString(EntranceUtils.KEY_ANSWER_CONTENT);
mQuestionsId = arguments.getString(EntranceUtils.KEY_QUESTIONS_ID);
mQuestionsTitle = arguments.getString(EntranceUtils.KEY_QUESTIONS_TITLE);
mCommunityName = arguments.getString(EntranceUtils.KEY_COMMUNITY_NAME);
mOpenAnswerInNewPage = arguments.getBoolean(EntranceUtils.KEY_ANSWER_OPEN_IN_NEW_PAGE);
mDraftId = arguments.getString(EntranceUtils.KEY_DRAFT_ID);
if (TextUtils.isEmpty(mAnswerId)) {
mBaseHandler.sendEmptyMessageDelayed(1, SAVE_DRAFTS_INTERVAL_TIME); // 启动自动保持
}
}
}
@Override
protected int getLayoutId() {
return R.layout.fragment_answer_edit;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mTitle.setText(mQuestionsTitle);
mEditContent.setPadding(20, 15, 20, 15);
mEditContent.setOnTextChangeListener((t) -> {
if (t.contains("<img src") || !TextUtils.isEmpty(mEditContent.getText())) {
mEditPlaceholder.setVisibility(View.GONE);
} else {
mEditPlaceholder.setVisibility(View.VISIBLE);
}
});
mEditContent.setOnInitialLoadListener(isReady -> {
if (isReady) {
mEditContent.scrollTo(0, 10000000);
try {
InputMethodManager imm = (InputMethodManager)
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(mEditContent, InputMethodManager.SHOW_IMPLICIT);
} catch (Exception e) {
e.printStackTrace();
}
mEditContent.postDelayed(() -> mEditContent.focusEditor(), 800);
}
});
if (!TextUtils.isEmpty(mAnswerId)) {
setNavigationTitle(getString(R.string.answer_patch_title));
mCacheAnswerContent = mAnswerContent;
mEditContent.setHtml(mAnswerContent, false);
} else {
setNavigationTitle(getString(R.string.answer_edit_title));
getUserAnswerDrafts();
}
// 防止个别手机在Js里无法获取粘贴内容
mEditContent.addJavascriptInterface(new onPasteListener(), "onPasteListener");
}
@Override
public void onMenuItemClick(MenuItem menuItem) {
if (menuItem.getItemId() == R.id.menu_answer_post && !ClickUtils.isFastDoubleClick(R.id.menu_answer_post, 5000)) {
postAnswer();
}
}
private void postImg(String picturePath) {
if (getContext() == null) return;
postDialog = WaitingDialogFragment.newInstance(getString(R.string.post_img));
postDialog.show(getChildFragmentManager(), null, () -> {
if (mUploadImageDisposable != null && !mUploadImageDisposable.isDisposed()) {
mUpdateImageCancelDialog = DialogUtils.showAlertDialog(getContext(), "提示", "图片正在上传中,确定取消吗?"
, "确定", "取消", () -> {
mUploadImageDisposable.dispose();
if (postDialog != null) postDialog.dismissAllowingStateLoss();
if (mUpdateImageCancelDialog != null) {
mUpdateImageCancelDialog.dismiss();
}
}, null);
}
});
mUploadImageDisposable = UploadImageUtils.INSTANCE.compressAndUploadImage(UploadImageUtils.UploadType.answer
, picturePath, false, new UploadImageUtils.OnUploadImageListener() {
@Override
public void onProgress(long total, long progress) {
int percent = (int) (100 * (progress / (float) total));
if (percent >= 100) percent = 99;
if (postDialog != null) {
postDialog.uploadWaitingHint("图片上传中 " + percent + "%");
}
}
@Override
public void onSuccess(@NotNull String imageUrl) {
if (postDialog != null) postDialog.dismissAllowingStateLoss();
if (mUpdateImageCancelDialog != null) mUpdateImageCancelDialog.dismiss();
mMapImg.put(TextUtils.htmlEncode(picturePath), imageUrl);
mEditContent.insertImage(FILE_HOST + picturePath);
}
@Override
public void onError(@org.jetbrains.annotations.Nullable Throwable e) {
if (postDialog != null) postDialog.dismissAllowingStateLoss();
if (mUpdateImageCancelDialog != null) mUpdateImageCancelDialog.dismiss();
if (e != null && e instanceof HttpException && ((HttpException) e).code() == 403) {
toast("图片违规");
} else {
toast("图片上传失败,请检查网络");
}
}
});
}
public void postAnswer() {
if (getContext() == null) return;
CheckLoginUtils.checkLogin(getContext(), "回答编辑-提交", () -> {
postDialog = WaitingDialogFragment.newInstance(getString(R.string.vote_post));
postDialog.show(getChildFragmentManager(), null);
String answerContent = mEditContent.getHtml();
for (String s : mMapImg.keySet()) {
answerContent = answerContent.replace(FILE_HOST + s, mMapImg.get(s));
}
post(answerContent);
if (CommonDebug.IS_DEBUG) Utils.log("answerEditHtml:" + answerContent);
});
}
private void post(String editContent) {
int answerLength = mEditContent.getText().length();
if (answerLength < MIN_ANSWER_TEXT_LENGTH) {
if (postDialog != null) postDialog.dismissAllowingStateLoss();
toast(R.string.answer_beneath_length_limit);
return;
} else if (answerLength > MAX_ANSWER_TEXT_LENGTH) {
if (postDialog != null) postDialog.dismissAllowingStateLoss();
DialogUtils.showAlertDialog(getContext(),
getString(R.string.answer_post_failed),
getString(R.string.answer_exceed_length_limit, MAX_ANSWER_TEXT_LENGTH, (answerLength - MAX_ANSWER_TEXT_LENGTH)),
getString(R.string.answer_resume_edit), "", () -> {
// do nothing
}, null);
return;
}
JSONObject content = new JSONObject();
try {
content.put("content", editContent);
} catch (JSONException e) {
e.printStackTrace();
}
RequestBody body = RequestBody.create(MediaType.parse("application/json"), content.toString());
Observable<ResponseBody> observable;
if (!TextUtils.isEmpty(mAnswerId)) {
if (editContent.equals(mAnswerContent)) { // 内容不变不需要请求服务器,直接返回成功即可
ResponseBody responseBody = new RealResponseBody("", 0, null);
observable = Single.just(responseBody).toObservable();
} else {
observable = RetrofitManager.getInstance(getContext()).getApi().patchQuestionAnswer(body, mAnswerId);
}
} else {
observable = RetrofitManager.getInstance(getContext()).getApi().postQuestionAnswer(body, mQuestionsId);
}
observable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<ResponseBody>() {
@Override
public void onResponse(ResponseBody response) {
super.onResponse(response);
MtaHelper.onEvent("发表答案", "提交成功", mCommunityName);
if (postDialog != null) postDialog.dismissAllowingStateLoss();
toast("发布成功");
String answerId = null;
try {
JSONObject object = new JSONObject(response.string());
answerId = object.getString("_id");
} catch (Exception e) {
e.printStackTrace();
}
if (getActivity() != null) {
Intent data = new Intent();
data.putExtra(EntranceUtils.KEY_ANSWER_CONTENT, editContent);
data.putExtra(EntranceUtils.KEY_ANSWER_ID, answerId);
getActivity().setResult(Activity.RESULT_OK, data);
if (mOpenAnswerInNewPage) {
Intent intent = AnswerDetailActivity.getIntent(getContext(), answerId, mEntrance, "编辑答案");
getActivity().startActivity(intent);
}
getActivity().finish();
}
}
@Override
public void onFailure(HttpException e) {
super.onFailure(e);
if (postDialog != null) postDialog.dismissAllowingStateLoss();
String errorString = null;
if (e != null && e.code() == 403) {
try {
errorString = e.response().errorBody().string();
JSONObject object = new JSONObject(errorString);
int code = object.getInt("code");
if (code == 403037) {
if (TextUtils.isEmpty(mDraftId)) {
DialogUtils.showAlertDialog(getContext(), "发布失败"
, "问题已被删除,无法发布回答"
, "好吧", ""
, () -> {
if (getActivity() != null) {
getActivity().finish();
}
}, null);
} else {
DialogUtils.showAlertDialog(getContext(), "发布失败"
, "问题已被删除,需要删除草稿吗?"
, "删除草稿", "暂不"
, () -> {
deleteAnswerDraft();
}, () -> {
if (getActivity() != null) {
getActivity().finish();
}
});
}
return;
} else {
ErrorHelper.INSTANCE.handleError(requireContext(), errorString, false);
return;
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
ErrorHelper.INSTANCE.handleError(requireContext(), errorString, false);
}
});
}
void deleteAnswerDraft() {
RetrofitManager.getInstance(getContext()).getApi()
.deleteAnswerDrafts(UserManager.getInstance().getUserId(), mDraftId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<ResponseBody>() {
@Override
public void onResponse(ResponseBody response) {
if (getActivity() != null) {
getActivity().setResult(Activity.RESULT_OK);
getActivity().finish();
}
}
@Override
public void onFailure(HttpException e) {
toast(R.string.loading_network_error);
}
});
}
@Override
public boolean onBackPressed() {
if (TextUtils.isEmpty(UserManager.getInstance().getToken())) {
return false;
} else if (!TextUtils.isEmpty(mAnswerId)) {
showPatchBackDialog();
return true;
} else if (TextUtils.isEmpty(mEditContent.getHtml()) ||
!TextUtils.isEmpty(mCacheAnswerContent) && mCacheAnswerContent.equals(mEditContent.getHtml())) {
return false;
} else {
saveAnswerDrafts(true);
return true;
}
}
private void showDraftFailureDialog() {
DialogUtils.showAlertDialog(getContext(),
"提示",
"确定退出?已撰写的内容将会丢失",
"继续撰写", "退出",
null, () -> {
if (getActivity() != null) getActivity().finish();
});
}
private void showPatchBackDialog() {
DialogUtils.showCancelAlertDialog(getActivity(), "提示", "确定退出修改?已修改的内容将丢失"
, "继续写", " 退出", null, () -> {
if (getActivity() != null) getActivity().finish();
});
}
private void saveAnswerDrafts(boolean isExit) {
String editContent = mEditContent.getHtml();
for (String s : mMapImg.keySet()) {
editContent = editContent.replace(FILE_HOST + s, mMapImg.get(s));
}
if (TextUtils.isEmpty(UserManager.getInstance().getToken())) {
return;
} else if (isExit && TextUtils.isEmpty(editContent) && getActivity() != null) {
getActivity().finish();
return;
} else if (!isExit && TextUtils.isEmpty(editContent)) { // || editContent.equals(mCacheAnswerContent)
return;
}
JSONObject content = new JSONObject();
try {
content.put("content", editContent);
content.put("question_id", mQuestionsId);
} catch (JSONException e) {
e.printStackTrace();
}
RequestBody body = RequestBody.create(MediaType.parse("application/json"), content.toString());
String finalEditContent = editContent;
RetrofitManager.getInstance(getContext()).getApi()
.postAnswerDrafts(body, UserManager.getInstance().getUserId())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<ResponseBody>() {
@Override
public void onResponse(ResponseBody response) {
super.onResponse(response);
if (getActivity() != null && isExit) {
Intent data = new Intent();
data.putExtra(EntranceUtils.KEY_ANSWER_CONTENT, finalEditContent);
getActivity().setResult(SAVE_DRAFTS, data);
getActivity().finish();
toast("回答已保存到草稿箱");
EventBus.getDefault().post(new EBReuse(ANSWER_DRAFT_CHANGE_TAG));
} else if (!isExit) {
if (mPostDraftsCount >= SAVE_DRAFTS_TOAST_COUNT) {
mPostDraftsCount = 0;
toast("回答已保存到草稿箱");
} else {
mPostDraftsCount++;
}
mCacheAnswerContent = finalEditContent;
}
}
@Override
public void onFailure(HttpException e) {
super.onFailure(e);
// toast("保存失败");
// AskErrorResponseUtils.errorResponseControl(getContext(), e);
if (isExit) showDraftFailureDialog();
}
});
}
private void getUserAnswerDrafts() {
RetrofitManager.getInstance(getContext()).getApi()
.getUserAnswerDrafts(mQuestionsId, Utils.getTime(getContext()))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<ResponseBody>() {
@Override
public void onResponse(ResponseBody response) {
super.onResponse(response);
try {
JSONObject object = new JSONObject(response.string());
String drafts = object.getString("content");
if (!TextUtils.isEmpty(drafts)) {
mEditContent.setHtml(drafts, false);
mCacheAnswerContent = drafts;
}
String answerId = object.getString("answer_id");
if (!TextUtils.isEmpty(answerId)) { // answerId不为空 表示已经提交过答案了
mAnswerId = answerId;
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onFailure(HttpException e) {
super.onFailure(e);
}
});
}
@OnClick({R.id.answer_edit_img_icon})
public void onClick(View view) {
if (view.getId() == R.id.answer_edit_img_icon) {
MtaHelper.onEvent("发表答案", "上传图片", mCommunityName);
if (!mAgreePostPic && !NetworkUtils.isWifiOr4GOr3GConnected(getContext())) {
mAgreePostPic = true;
DialogUtils.showAlertDialog(getContext(),
"警告",
"当前使用移动网络,上传图片会消耗手机流量",
"我知道了", "", () -> startMediaStore(), null);
MtaHelper.onEvent("发表答案", "上传图片-移动网络提示", mCommunityName);
return;
}
startMediaStore();
}
}
private void startMediaStore() {
if (mMapImg.size() >= 50) {
toast(R.string.answer_edit_max_img_hint);
return;
}
try {
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, SelectPortraitFragment.REQUEST_MEDIA_ICON);
} catch (Exception e) {
toast(R.string.media_image_hint);
e.printStackTrace();
}
}
private class onPasteListener {
@JavascriptInterface
public void onPaste() {
ClipboardManager clipboard = (ClipboardManager)
HaloApp.getInstance().getApplication().getSystemService(Context.CLIPBOARD_SERVICE);
if (clipboard != null && !TextUtils.isEmpty(clipboard.getText().toString())) {
// 替换换行符号否则 插入失败
String text = clipboard.getText().toString().replaceAll("[\r\n]", "");
mBaseHandler.post(() -> mEditContent.insertHtml(text));
}
}
}
}

View File

@ -0,0 +1,235 @@
package com.gh.gamecenter.qa.answer.edit
import android.app.Application
import android.arch.lifecycle.AndroidViewModel
import android.arch.lifecycle.MediatorLiveData
import android.arch.lifecycle.ViewModel
import android.arch.lifecycle.ViewModelProvider
import android.content.Intent
import android.text.TextUtils
import com.gh.base.fragment.WaitingDialogFragment
import com.gh.common.util.ImageUtils
import com.gh.common.util.UploadImageUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.eventbus.EBReuse
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.mvvm.Resource
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.lightgame.utils.Utils
import com.zhihu.matisse.Matisse
import com.zhihu.matisse.internal.utils.PathUtils
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.RequestBody
import okhttp3.ResponseBody
import okhttp3.internal.http.RealResponseBody
import org.greenrobot.eventbus.EventBus
import org.json.JSONException
import org.json.JSONObject
import retrofit2.HttpException
import java.io.File
import java.util.*
class AnswerEditViewModel(application: Application,
var answerId: String?, // 以mAnswerId为标识如果mAnswerId不为空则是-修改答案(不需要保存草稿) 为空则是-编写答案
var answerContent: String?,
var draftId: String?,
var questionsId: String?) : AndroidViewModel(application) {
private var mPostDraftsCount: Int = 0
private val mApi = RetrofitManager.getInstance(getApplication()).api
var cacheAnswerContent: String? = null
val processDialog = MediatorLiveData<WaitingDialogFragment.WaitingDialogData>()
val postLiveData = MediatorLiveData<Resource<ResponseBody>>()
val postImageLiveData = MediatorLiveData<Resource<Map<String, String>>>()
val deleteDraftLiveDate = MediatorLiveData<Boolean>()
val draftsLiveData = MediatorLiveData<String>()
val saveDraftsLiveData = MediatorLiveData<Boolean>() // 自动保存不会回调
var uploadImageSubscription: Disposable? = null
val mapImages = HashMap<String, String>()
fun postAnswer(editContent: String) {
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("提交中...", true))
val content = JSONObject()
try {
content.put("content", editContent)
} catch (e: JSONException) {
e.printStackTrace()
}
val body = RequestBody.create(MediaType.parse("application/json"), content.toString())
val observable = if (!TextUtils.isEmpty(answerId)) {
if (editContent == answerContent) { // 内容不变不需要请求服务器,直接返回成功即可
val responseBody = RealResponseBody("", 0, null)
Single.just<ResponseBody>(responseBody).toObservable()
} else {
mApi.patchQuestionAnswer(body, answerId)
}
} else {
mApi.postQuestionAnswer(body, questionsId)
}
observable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("提交中...", false))
postLiveData.postValue(Resource.success(response))
}
override fun onFailure(e: HttpException?) {
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("提交中...", false))
postLiveData.postValue(Resource.error(e))
}
})
}
fun deleteAnswerDraft() {
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("删除中...", true))
mApi
.deleteAnswerDrafts(UserManager.getInstance().userId, draftId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("删除中...", false))
deleteDraftLiveDate.postValue(true)
}
override fun onFailure(e: HttpException?) {
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("删除中...", false))
deleteDraftLiveDate.postValue(false)
Utils.toast(getApplication(), R.string.loading_network_error)
}
})
}
fun postImg(data: Intent) {
val uris = Matisse.obtainResult(data)
val pictureList = ArrayList<String>()
for (uri in uris) {
val picturePath = PathUtils.getPath(getApplication(), uri)
if (File(picturePath).length() > ImageUtils.getUploadFileMaxSize()) {
val count = ImageUtils.getUploadFileMaxSize() / 1024 / 1024
val application: Application = getApplication()
Utils.toast(getApplication(), application.getString(R.string.pic_max_hint, count))
continue
}
Utils.log("picturePath = $picturePath")
pictureList.add(picturePath)
}
if (pictureList.size == 0) return
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("上传中...", true))
uploadImageSubscription = UploadImageUtils.compressAndUploadImageList(UploadImageUtils.UploadType.answer, pictureList
, false, object : UploadImageUtils.OnUploadImageListListener {
override fun onProgress(total: Long, progress: Long) {
var percent = (100 * (progress / total.toFloat())).toInt()
if (percent >= 100) percent = 99
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("图片上传中 $percent%", true))
}
override fun onSuccess(imageUrl: Map<String, String>) {
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("上传中...", false))
postImageLiveData.postValue(Resource.success(imageUrl))
}
override fun onError() { // todo 失败提示??????
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("上传中...", false))
Utils.toast(getApplication(), "图片上传失败,请检查网络")
postImageLiveData.postValue(Resource.error(null))
// if (e != null && e instanceof HttpException && ((HttpException) e).code() == 403) {
// toast("图片违规");
// } else {
// toast("图片上传失败,请检查网络");
// }
}
})
}
fun getUserAnswerDrafts() {
mApi
.getUserAnswerDrafts(questionsId, Utils.getTime(getApplication()))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
try {
val string = JSONObject(response!!.string())
val drafts = string.getString("content")
if (!TextUtils.isEmpty(drafts)) {
draftsLiveData.postValue(drafts)
cacheAnswerContent = drafts
}
val oldAnswerId = string.getString("answer_id")
if (!TextUtils.isEmpty(oldAnswerId)) { // answerId不为空 表示已经提交过答案了
answerId = oldAnswerId
}
} catch (e: Exception) {
e.printStackTrace()
}
}
})
}
fun saveAnswerDrafts(editContent: String, isExit: Boolean) {
val content = JSONObject()
try {
content.put("content", editContent)
content.put("question_id", questionsId)
} catch (e: JSONException) {
e.printStackTrace()
}
val body = RequestBody.create(MediaType.parse("application/json"), content.toString())
mApi
.postAnswerDrafts(body, UserManager.getInstance().userId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
if (isExit) {
saveDraftsLiveData.postValue(true)
Utils.toast(getApplication(), "回答已保存到草稿箱")
EventBus.getDefault().post(EBReuse(AnswerEditActivity.ANSWER_DRAFT_CHANGE_TAG))
} else if (!isExit) {
if (mPostDraftsCount >= AnswerEditActivity.SAVE_DRAFTS_TOAST_COUNT) {
mPostDraftsCount = 0
Utils.toast(getApplication(), "回答已保存到草稿箱")
} else {
mPostDraftsCount++
}
cacheAnswerContent = editContent
}
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
if (isExit) saveDraftsLiveData.postValue(false)
}
})
}
class Factory(private val mApplication: Application,
private val answerId: String?,
private val answerContent: String?,
private val draftId: String?,
private val questionsId: String?) : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return AnswerEditViewModel(mApplication, answerId, answerContent, draftId, questionsId) as T
}
}
}

View File

@ -1,6 +1,5 @@
package com.gh.gamecenter.qa.article.detail
import android.animation.Animator
import android.app.Activity
import android.app.Dialog
import android.arch.lifecycle.Lifecycle
@ -25,7 +24,7 @@ import butterknife.OnClick
import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.drawee.controller.BaseControllerListener
import com.facebook.fresco.animation.drawable.AnimatedDrawable2
import com.facebook.fresco.animation.drawable.AnimationListener
import com.facebook.fresco.animation.drawable.BaseAnimationListener
import com.gh.base.BaseActivity
import com.gh.common.TimeElapsedHelper
import com.gh.common.TimeoutCallback
@ -37,11 +36,13 @@ import com.gh.gamecenter.SuggestionActivity
import com.gh.gamecenter.ViewImageActivity
import com.gh.gamecenter.databinding.ActivityArticleDetailBinding
import com.gh.gamecenter.entity.CommunityEntity
import com.gh.gamecenter.entity.MeEntity
import com.gh.gamecenter.entity.SpecialColumn
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.mvvm.Status
import com.gh.gamecenter.qa.article.edit.ArticleEditActivity
import com.gh.gamecenter.qa.comment.CommentActivity
import com.gh.gamecenter.qa.entity.ArticleDetailEntity
import com.gh.gamecenter.suggest.SuggestType
import com.google.android.flexbox.FlexboxLayout
import com.qq.gdt.action.ActionType
@ -179,6 +180,37 @@ class ArticleDetailActivity : BaseActivity() {
}
}
mViewModel.highlight.observeNonNull(this) { isHighlighted ->
if (isHighlighted) {
if (MeEntity.MODERATOR_LEVEL_PRIMARY == mViewModel.detailEntity!!.me.moderatorLevel) {
toast("提交成功")
} else {
toast("操作成功")
finish()
}
} else {
toast("权限错误,请刷新后重试")
}
}
mViewModel.hide.observeNonNull(this) { isHidden ->
if (isHidden) {
if (MeEntity.MODERATOR_LEVEL_PRIMARY == mViewModel.detailEntity!!.me.moderatorLevel) {
toast("提交成功")
} else {
toast("操作成功")
mViewModel.getArticleDetail()
}
} else {
toast("权限错误,请刷新后重试")
}
}
mViewModel.commentable.observeNonNull(this) { enable ->
mViewModel.detailEntity?.commentable = enable
updateCommentable(enable)
}
mBinding.articleDetailRd.addJavascriptInterface(JsInterface(), "imagelistener")
if (mIsShowCommentManager) {
@ -188,6 +220,15 @@ class ArticleDetailActivity : BaseActivity() {
mElapsedHelper = TimeElapsedHelper(this)
}
private fun updateCommentable(commentable: Boolean) {
if (commentable) {
mBinding.articleDetailCommentCountTv.text = String.format("%d 评论",
mViewModel.detailEntity?.count?.comment ?: 0)
} else {
mBinding.articleDetailCommentCountTv.text = "评论已关闭"
}
}
/**
* 开启点赞引导动画倒计时
*/
@ -209,32 +250,14 @@ class ArticleDetailActivity : BaseActivity() {
.setUri(uri)
.setAutoPlayAnimations(true)
.setControllerListener(object : BaseControllerListener<Any>() {
override fun onFinalImageSet(id: String?,
imageInfo: Any?,
animatable: Animatable?) {
override fun onFinalImageSet(id: String?, imageInfo: Any?, animatable: Animatable?) {
if (animatable != null) {
val animatedDrawable = animatable as AnimatedDrawable2?
animatedDrawable!!.setAnimationListener(object : AnimationListener {
override fun onAnimationStart(drawable: AnimatedDrawable2) {
}
animatedDrawable!!.setAnimationListener(object : BaseAnimationListener() {
override fun onAnimationStop(drawable: AnimatedDrawable2) {
mBinding.articleDetailCommentLikeAnimationIv.visibility = View.GONE
updateVote()
}
override fun onAnimationReset(drawable: AnimatedDrawable2) {
}
override fun onAnimationRepeat(drawable: AnimatedDrawable2) {
}
override fun onAnimationFrame(drawable: AnimatedDrawable2, frameNumber: Int) {
}
})
}
}
@ -278,12 +301,14 @@ class ArticleDetailActivity : BaseActivity() {
fun onClick(v: View) {
when (v.id) {
R.id.article_detail_comment_count_container -> {
if (mViewModel.detailEntity != null) {
if (mViewModel.detailEntity != null == mViewModel.detailEntity!!.commentable) {
val intent = CommentActivity.getArticleCommentIntent(this, mViewModel.articleId!!
, mViewModel.detailEntity?.count?.comment, ""
, mViewModel.detailEntity?.count?.comment == 0
, mViewModel.detailEntity?.community?.id!!)
startActivityForResult(intent, CommentActivity.REQUEST_CODE)
} else {
toast("作者已关闭评论")
}
}
R.id.article_detail_like_container -> {
@ -320,7 +345,8 @@ class ArticleDetailActivity : BaseActivity() {
}
}
}
R.id.article_detail_usericon_container, R.id.article_detail_username -> {
R.id.article_detail_usericon_container,
R.id.article_detail_username -> {
if (mViewModel.detailEntity != null) {
PersonalHomeActivity.startTargetActivity(this,
mViewModel.detailEntity?.user?.id, mEntrance, "社区文章详情")
@ -340,23 +366,11 @@ class ArticleDetailActivity : BaseActivity() {
mBinding.articleDetailFollow.animate()
.alpha(0f)
.setInterpolator(LinearInterpolator())
.setListener(object : Animator.AnimatorListener {
override fun onAnimationStart(animation: Animator) {
}
override fun onAnimationEnd(animation: Animator) {
.doOnEnd {
if (this != null && !this.isFinishing) {
mBinding.articleDetailFollow.visibility = View.GONE
}
override fun onAnimationCancel(animation: Animator) {
}
override fun onAnimationRepeat(animation: Animator) {
}
})
}
.setDuration(500L)
.start()
}, 2000L)
@ -372,10 +386,10 @@ class ArticleDetailActivity : BaseActivity() {
&& mViewModel.detailEntity != null
&& !mViewModel.detailEntity!!.me.isAnswerOwn) {
mBinding.tvFollowHint.visibility = View.VISIBLE
mBinding.tvFollowHint.animate()
.alpha(0f)
.setDuration(750)
.start()
mBinding.tvFollowHint.animate()
.alpha(0f)
.setDuration(750)
.start()
}
}
@ -427,27 +441,71 @@ class ArticleDetailActivity : BaseActivity() {
window.attributes = lp
}
dialog.show()
val itemName1 = view.findViewById<TextView>(R.id.more_item_title1)
val itemIcon1 = view.findViewById<ImageView>(R.id.more_item_icon1)
val item1 = view.findViewById<View>(R.id.more_item1)
val item2 = view.findViewById<View>(R.id.more_item2)
if (mViewModel.detailEntity?.user?.id == UserManager.getInstance().userId) {
itemName1.text = "编辑文章"
itemIcon1.setImageResource(R.drawable.menu_more_edit)
val reportContainer = view.findViewById<View>(R.id.container_report)
val reportTv = view.findViewById<TextView>(R.id.tv_report)
val reportIv = view.findViewById<ImageView>(R.id.iv_report)
val shareContainer = view.findViewById<View>(R.id.container_share)
val commentControlContainer = view.findViewById<View>(R.id.container_comment_control)
if (mViewModel.detailEntity?.me!!.isModerator) {
val controlView = view.findViewById<View>(R.id.container_control)
controlView.visibility = View.VISIBLE
controlView.setOnClickListener {
showControlDialog(mViewModel.detailEntity!!)
dialog.dismiss()
}
}
item1.setOnClickListener { _ ->
if (mViewModel.detailEntity?.user?.id == UserManager.getInstance().userId) {
reportTv.text = "编辑文章"
reportIv.setImageResource(R.drawable.menu_more_edit)
}
if (mViewModel.detailEntity?.me!!.isAnswerOwn) {
commentControlContainer.visibility = View.VISIBLE
val commentControlTv = commentControlContainer.findViewById<TextView>(R.id.tv_comment_control)
val commentControlIv = commentControlContainer.findViewById<ImageView>(R.id.iv_comment_control)
if (mViewModel.detailEntity?.commentable!!) {
commentControlIv.setImageResource(R.drawable.ic_close_comment)
commentControlTv.text = "关闭评论"
} else {
commentControlIv.setImageResource(R.drawable.ic_open_comment)
commentControlTv.text = "恢复评论"
}
commentControlContainer.setOnClickListener {
dialog.dismiss()
if (mViewModel.detailEntity?.commentable!!) {
DialogUtils.showAlertDialog(this, "提示", "关闭评论之后,该回答将无法查看和发表评论,确定关闭吗?",
"确定", "取消", {
mViewModel.toggleComment(
mViewModel.detailEntity?.community!!.id,
mViewModel.articleId!!,
false)
}, null)
} else {
DialogUtils.showAlertDialog(this, "提示", "确定恢复评论吗?",
"确定", "取消", {
mViewModel.toggleComment(
mViewModel.detailEntity?.community!!.id,
mViewModel.articleId!!,
true)
}, null)
}
}
}
reportContainer.setOnClickListener {
dialog.dismiss()
if (mViewModel.detailEntity?.user?.id == UserManager.getInstance().userId) {
startActivityForResult(ArticleEditActivity.getPatchIntent(this, mViewModel.detailEntity!!), ARTICLE_PATCH_REQUEST)
} else {
// 跳转意见反馈
SuggestionActivity.startSuggestionActivity(this, SuggestType.normal, "report",
"文章举报(" + mViewModel.articleId + "")
}
}
item2.setOnClickListener { _ ->
shareContainer.setOnClickListener {
dialog.dismiss()
GdtHelper.logAction(ActionType.SHARE,
@ -471,6 +529,46 @@ class ArticleDetailActivity : BaseActivity() {
}
}
private fun showControlDialog(article: ArticleDetailEntity) {
val permissionList = article.me.moderatorPermissions
val moderatorLevel = article.me.moderatorLevel
val highlight = "加精文章"
val hide = "隐藏文章"
val displayablePermissionList = ArrayList<String>()
if (permissionList.contains(MeEntity.CHOICENESS_COMMUNITY_ARTICLE)
&& !mViewModel.detailEntity?.me!!.isAnswerOwn) {
displayablePermissionList.add(highlight)
}
if (permissionList.contains(MeEntity.HIDE_COMMUNITY_ARTICLE)) {
displayablePermissionList.add(hide)
}
DialogUtils.showListDialog(this, displayablePermissionList, null) { text ->
val content: String = if (MeEntity.MODERATOR_LEVEL_PRIMARY == moderatorLevel) {
"你的操作将提交给小编审核,确定提交吗?"
} else {
"你的操作将立即生效,确定提交吗?(你的管理权限为:高级)"
}
when (text) {
highlight -> {
DialogUtils.showAlertDialog(this, highlight, content,
"确定", "取消",
{ mViewModel.doHighlightThisArticle(mViewModel.detailEntity!!.community.id, mViewModel.articleId) }, null)
}
hide -> {
DialogUtils.showAlertDialog(this, hide, content,
"确定", "取消",
{ mViewModel.doHideThisArticle(mViewModel.detailEntity!!.community.id, mViewModel.articleId) }, null)
}
}
}
}
private fun updateView() {
if (mViewModel.detailEntity == null) return
mCollectMenuItem = getMenuItem(R.id.menu_collect)
@ -483,7 +581,8 @@ class ArticleDetailActivity : BaseActivity() {
mBinding.detail = mViewModel.detailEntity
mBinding.articleDetailRd.setHtml(mViewModel.detailEntity?.content, true)
mBinding.articleDetailCommentCountTv.text = String.format("%d 评论", mViewModel.detailEntity?.count?.comment)
mBinding.articleDetailCommentCountTv.text = String.format("%s 评论",
NumberUtils.transSimpleCount(mViewModel.detailEntity?.count?.comment!!))
// 没点赞过作者不是自己正文长度不少于20个字。 开启停留一定时长(字数/10 + 5秒)后的动画
if (!mViewModel.detailEntity!!.me.isAnswerOwn
@ -538,6 +637,7 @@ class ArticleDetailActivity : BaseActivity() {
}
}
updateCommentable(mViewModel.detailEntity?.commentable!!)
updateVote()
}
@ -572,7 +672,6 @@ class ArticleDetailActivity : BaseActivity() {
override fun onDestroy() {
super.onDestroy()
if (mViewModel.detailEntity != null) {
MtaHelper.onEventWithTime(
"文章阅读量_社区加位置",
mElapsedHelper?.elapsedTime!!,
@ -583,7 +682,8 @@ class ArticleDetailActivity : BaseActivity() {
mViewModel.articleId,
mViewModel.detailEntity?.title,
mElapsedHelper?.elapsedTime!!,
mViewModel.detailEntity?.community, mSpecialColumn)
mViewModel.detailEntity?.community,
mSpecialColumn)
}
}

View File

@ -17,24 +17,31 @@ import com.gh.gamecenter.retrofit.RetrofitManager
import com.lightgame.utils.Utils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.RequestBody
import okhttp3.ResponseBody
import org.greenrobot.eventbus.EventBus
import org.json.JSONObject
import retrofit2.HttpException
import java.util.*
class ArticleDetailViewModel(application: Application) : AndroidViewModel(application) {
private val mApi = RetrofitManager.getInstance(getApplication()).api
var detailEntity: ArticleDetailEntity? = null
val articleLiveData = MutableLiveData<Resource<ArticleDetailEntity>>()
private val mFollowLiveData = MutableLiveData<Boolean>()
private var community: CommunityEntity? = null // 社区名称可能为空
val hide = MutableLiveData<Boolean>()
val vote = MutableLiveData<VoteEntity>()
val highlight = MutableLiveData<Boolean>()
val commentable = MutableLiveData<Boolean>()
val articleLiveData = MutableLiveData<Resource<ArticleDetailEntity>>()
val followLiveData: LiveData<Boolean>
get() = mFollowLiveData
val vote = MutableLiveData<VoteEntity>()
private var community: CommunityEntity? = null // 社区名称可能为空
var articleId: String? = null
@ -143,4 +150,57 @@ class ArticleDetailViewModel(application: Application) : AndroidViewModel(applic
}
})
}
fun doHighlightThisArticle(communityId: String, articleId: String?) {
mApi.highlightCommunityArticle(communityId, articleId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
highlight.postValue(true)
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
highlight.postValue(false)
}
})
}
fun doHideThisArticle(communityId: String, articleId: String?) {
mApi.hideCommunityArticle(communityId, articleId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
hide.postValue(true)
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
hide.postValue(false)
}
})
}
fun toggleComment(communityId: String, articleId: String, isCommentable: Boolean) {
val params = HashMap<String, Boolean>()
params["commentable"] = isCommentable
val body = RequestBody.create(MediaType.parse("application/json"),
JSONObject(params).toString())
mApi.postCommunityArticleCommentable(communityId, articleId, body)
.subscribeOn(Schedulers.io())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
commentable.postValue(isCommentable)
}
override fun onFailure(e: HttpException?) {
Utils.toast(getApplication(), e?.message())
}
})
}
}

View File

@ -10,7 +10,6 @@ import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.os.Message
import android.provider.MediaStore
import android.support.v7.widget.GridLayoutManager
import android.support.v7.widget.RecyclerView
import android.text.Html
@ -25,26 +24,27 @@ import android.widget.EditText
import android.widget.ProgressBar
import android.widget.TextView
import butterknife.OnClick
import com.gh.base.BaseActivity
import com.gh.base.BaseRichEditorActivity
import com.gh.base.fragment.BaseDialogWrapperFragment
import com.gh.base.fragment.WaitingDialogFragment
import com.gh.common.util.*
import com.gh.common.view.RichEditor
import com.gh.gamecenter.R
import com.gh.gamecenter.SuggestionActivity
import com.gh.gamecenter.entity.CommunityEntity
import com.gh.gamecenter.eventbus.EBReuse
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.mvvm.Status
import com.gh.gamecenter.qa.answer.edit.AnswerEditActivity
import com.gh.gamecenter.qa.article.draft.ArticleDraftActivity
import com.gh.gamecenter.qa.entity.ArticleDetailEntity
import com.gh.gamecenter.qa.entity.ArticleDraftEntity
import com.gh.gamecenter.qa.questions.edit.TagsSelectFragment
import com.zhihu.matisse.Matisse
import com.zhihu.matisse.MimeType
import kotterknife.bindView
import org.greenrobot.eventbus.EventBus
class ArticleEditActivity : BaseActivity() {
class ArticleEditActivity : BaseRichEditorActivity() {
private val mEditContent by bindView<RichEditor>(R.id.article_edit_content)
private val mEditPlaceholder by bindView<View>(R.id.article_placeholder)
private val mGameNameTitle by bindView<TextView>(R.id.article_game_name_title)
private val mGameName by bindView<TextView>(R.id.article_game_name)
@ -65,10 +65,12 @@ class ArticleEditActivity : BaseActivity() {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
if (msg.what == 1) {
if (mViewModel?.mSelectCommunityData != null && !TextUtils.isEmpty(mEditTitle.text.trim()) &&
(!TextUtils.isEmpty(mEditContent.text) || mEditContent.html.contains("<img src"))) {
if (mViewModel?.mSelectCommunityData != null
&& !TextUtils.isEmpty(mEditTitle.text.trim())
&& (!TextUtils.isEmpty(mRichEditor.text)
|| mRichEditor.html.contains("<img src"))) {
mViewModel?.title = mEditTitle.text.toString()
mViewModel?.content = mEditContent.html
mViewModel?.content = mRichEditor.html
mViewModel?.postArticleDrafts(false)
}
mBaseHandler.sendEmptyMessageDelayed(1, SAVE_DRAFTS_INTERVAL_TIME.toLong())
@ -77,7 +79,7 @@ class ArticleEditActivity : BaseActivity() {
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (data != null && requestCode == SuggestionActivity.MEDIA_STORE_REQUEST) {
if (data != null && requestCode == REQUEST_CODE_IMAGE) {
mViewModel?.uploadPic(data)
} else if (requestCode == ArticleEditActivity.ARTICLE_DRAFT_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
val draftEntity = data?.getParcelableExtra<ArticleDraftEntity>(ArticleDraftEntity::class.java.simpleName)
@ -91,15 +93,15 @@ class ArticleEditActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setToolbarMenu(R.menu.menu_answer_post)
mDraftBtn.visibility = View.VISIBLE
mViewModel = ViewModelProviders.of(this).get(ArticleEditViewModel::class.java)
mViewModel?.detailEntity = intent.getParcelableExtra(ArticleDetailEntity::class.java.simpleName)
mViewModel?.draftEntity = intent.getParcelableExtra(ArticleDraftEntity::class.java.simpleName)
mGameNameTitle.text = Html.fromHtml(getString(R.string.article_edit_game_name))
mEditContent.setPadding(18, 15, 18, 15)
mEditContent.setOnTextChangeListener { t ->
if (t.contains("<img src") || !TextUtils.isEmpty(mEditContent.text)) {
mRichEditor.setPadding(18, 15, 18, 15)
mRichEditor.setOnTextChangeListener { t ->
if (t.contains("<img src") || !TextUtils.isEmpty(mRichEditor.text)) {
mEditPlaceholder.visibility = View.GONE
} else {
mEditPlaceholder.visibility = View.VISIBLE
@ -108,8 +110,14 @@ class ArticleEditActivity : BaseActivity() {
setEditTextInputSpace()
// 上传图片完成后的回调(本地图片)
mViewModel?.postImage?.observe(this, Observer {
mEditContent.insertImage(it)
mViewModel?.postImageLiveData?.observe(this, Observer {
if (it?.status == Status.SUCCESS) {
val imageUrl = it.data!!
for (sourceImage in imageUrl.keys) {
mViewModel?.mapImg?.set(TextUtils.htmlEncode(sourceImage), imageUrl[sourceImage]!!)
mRichEditor.insertImage(AnswerEditActivity.FILE_HOST + sourceImage)
}
}
})
// 保存草稿
@ -169,16 +177,17 @@ class ArticleEditActivity : BaseActivity() {
} else if (mViewModel?.draftEntity != null) {
setNavigationTitle("撰写文章")
setArticleDraft()
mBaseHandler.sendEmptyMessageDelayed(1, SAVE_DRAFTS_INTERVAL_TIME.toLong())
} else {// 启动自动保存草稿
setNavigationTitle("撰写文章")
// mBaseHandler.sendEmptyMessageDelayed(1, SAVE_DRAFTS_INTERVAL_TIME.toLong()) //暂时取消
mBaseHandler.sendEmptyMessageDelayed(1, SAVE_DRAFTS_INTERVAL_TIME.toLong())
}
}
@OnClick(R.id.article_game_name, R.id.article_edit_img_icon, R.id.article_edit_draft_btn)
@OnClick(R.id.article_game_name, R.id.editor_image, R.id.article_edit_draft_btn)
fun onClick(v: View) {
when (v.id) {
R.id.article_edit_img_icon -> {
R.id.editor_image -> {
MtaHelper.onEvent("发表文章", "上传图片", UserManager.getInstance().community.name)
if (!mAgreePostPic && !NetworkUtils.isWifiOr4GOr3GConnected(this)) {
mAgreePostPic = true
@ -221,8 +230,11 @@ class ArticleEditActivity : BaseActivity() {
}
try {
val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
startActivityForResult(intent, SuggestionActivity.MEDIA_STORE_REQUEST)
Matisse.from(this)
.choose(MimeType.ofAll())
.countable(true)
.maxSelectable(10)
.forResult(REQUEST_CODE_IMAGE)
} catch (e: Exception) {
toast(R.string.media_image_hint)
e.printStackTrace()
@ -250,12 +262,12 @@ class ArticleEditActivity : BaseActivity() {
}
private fun setEditHtml(html: String?) {
mEditContent.setHtml(html, false)
mRichEditor.setHtml(html, false)
try {
mEditContent.scrollTo(0, 10000000)
mRichEditor.scrollTo(0, 10000000)
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(mEditContent, InputMethodManager.SHOW_IMPLICIT)
mEditContent.postDelayed({ mEditContent.focusEditor() }, 800)
imm.showSoftInput(mRichEditor, InputMethodManager.SHOW_IMPLICIT)
mRichEditor.postDelayed({ mRichEditor.focusEditor() }, 800)
} catch (e: Exception) {
e.printStackTrace()
}
@ -279,20 +291,20 @@ class ArticleEditActivity : BaseActivity() {
if (draftEntity != null) {
if (draftEntity.community.id == mViewModel?.mSelectCommunityData?.id &&
draftEntity.title == mEditTitle.text.toString() &&
mViewModel?.articleDraftsContent?.value == mEditContent.html) {
mViewModel?.articleDraftsContent?.value == mRichEditor.html) {
return true
}
}
if (mEditContent.html.contains("<img src")
|| !TextUtils.isEmpty(mEditContent.text)
if (mRichEditor.html.contains("<img src")
|| !TextUtils.isEmpty(mRichEditor.text)
|| !TextUtils.isEmpty(mEditTitle.text.trim())) {
if (mViewModel?.mSelectCommunityData == null) {
showDraftFailureDialog()
return false
}
mViewModel?.title = mEditTitle.text.toString()
mViewModel?.content = mEditContent.html
mViewModel?.content = mRichEditor.html
mViewModel?.postArticleDrafts(isExit)
return false
}
@ -338,7 +350,7 @@ class ArticleEditActivity : BaseActivity() {
if (item?.itemId == R.id.menu_answer_post) {
ifLogin("社区文章编辑-[发布]") {
mViewModel?.title = mEditTitle.text.toString()
mViewModel?.content = mEditContent.html
mViewModel?.content = mRichEditor.html
mViewModel?.checkDataAndLoadTitleTag()
}
}
@ -362,6 +374,7 @@ class ArticleEditActivity : BaseActivity() {
companion object {
const val SAVE_DRAFTS_INTERVAL_TIME = 15000
const val ARTICLE_DRAFT_REQUEST_CODE = 105
const val REQUEST_CODE_IMAGE = 120
const val ARTICLE_DRAFT_CHANGE_TAG = "ANSWER_DRAFT_CHANGE_TAG"
@JvmStatic

View File

@ -5,19 +5,22 @@ import android.arch.lifecycle.AndroidViewModel
import android.arch.lifecycle.MediatorLiveData
import android.arch.lifecycle.MutableLiveData
import android.content.Intent
import android.provider.MediaStore
import android.text.TextUtils
import com.gh.base.fragment.WaitingDialogFragment
import com.gh.common.util.*
import com.gh.gamecenter.R
import com.gh.gamecenter.entity.CommunityEntity
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.mvvm.Resource
import com.gh.gamecenter.qa.answer.edit.AnswerEditActivity
import com.gh.gamecenter.qa.entity.ArticleDetailEntity
import com.gh.gamecenter.qa.entity.ArticleDraftEntity
import com.gh.gamecenter.qa.questions.edit.QuestionEditViewModel
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.lightgame.utils.Utils
import com.zhihu.matisse.Matisse
import com.zhihu.matisse.internal.utils.PathUtils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
@ -36,10 +39,12 @@ class ArticleEditViewModel(application: Application) : AndroidViewModel(applicat
val FILE_HOST = "file:///"
private var mPostDraftsCount: Int = 0
val MIN_ARTICLE_TEXT_LENGTH = 6
val processDialog = MediatorLiveData<WaitingDialogFragment.WaitingDialogData>()
val postImage = MediatorLiveData<String>()
val postImageLiveData = MediatorLiveData<Resource<Map<String, String>>>()
val postArticle = MediatorLiveData<String>()
val postArticleDrafts = MediatorLiveData<Boolean>()
val articleDraftsContent = MediatorLiveData<String>()
@ -141,49 +146,45 @@ class ArticleEditViewModel(application: Application) : AndroidViewModel(applicat
* @param picPath 图片本地路径
*/
fun uploadPic(data: Intent) {
val selectedImage = data.data ?: return
val filePathColumn = arrayOf(MediaStore.Images.Media.DATA)
val application: Application = getApplication()
val cursor = application.contentResolver.query(selectedImage, filePathColumn, null, null, null)
?: return
cursor.moveToFirst()
val columnIndex = cursor.getColumnIndex(filePathColumn[0])
val picPath = cursor.getString(columnIndex)
cursor.close()
Utils.log("picturePath = " + picPath)
val file = File(picPath)
if (file.length() > ImageUtils.getUploadFileMaxSize()) {
val count = ImageUtils.getUploadFileMaxSize() / 1024 / 1024
Utils.toast(getApplication(), getApplication<Application>().getString(R.string.pic_max_hint, count))
return
val uris = Matisse.obtainResult(data)
val pictureList = ArrayList<String>()
for (uri in uris) {
val picturePath = PathUtils.getPath(getApplication(), uri)
if (File(picturePath).length() > ImageUtils.getUploadFileMaxSize()) {
val count = ImageUtils.getUploadFileMaxSize() / 1024 / 1024
val application: Application = getApplication()
Utils.toast(getApplication(), application.getString(R.string.pic_max_hint, count))
continue
}
Utils.log("picturePath = $picturePath")
pictureList.add(picturePath)
}
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("上传中...6566", true))
uploadImageSubscription = UploadImageUtils.compressAndUploadImage(UploadImageUtils.UploadType.answer
, picPath, false, object : UploadImageUtils.OnUploadImageListener {
if (pictureList.size == 0) return
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("上传中...", true))
uploadImageSubscription = UploadImageUtils.compressAndUploadImageList(UploadImageUtils.UploadType.answer, pictureList
, false, object : UploadImageUtils.OnUploadImageListListener {
override fun onProgress(total: Long, progress: Long) {
var percent = (100 * (progress / total.toFloat())).toInt()
if (percent >= 100) percent = 99
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("图片上传中 $percent%", true))
}
override fun onSuccess(imageUrl: String) {
override fun onSuccess(imageUrl: Map<String, String>) {
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("上传中...", false))
mapImg[TextUtils.htmlEncode(picPath)] = imageUrl
postImage.postValue(FILE_HOST + picPath)
postImageLiveData.postValue(Resource.success(imageUrl))
}
override fun onError(e: Throwable?) {
override fun onError() { // todo 失败提示??????
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("上传中...", false))
if (e != null && e is HttpException && e.code() == 403) {
Utils.toast(getApplication(), "图片违规")
} else {
Utils.toast(getApplication(), "图片上传失败,请检查网络")
}
Utils.toast(getApplication(), "图片上传失败,请检查网络")
postImageLiveData.postValue(Resource.error(null))
// if (e != null && e instanceof HttpException && ((HttpException) e).code() == 403) {
// toast("图片违规");
// } else {
// toast("图片上传失败,请检查网络");
// }
}
})
}
@ -262,8 +263,17 @@ class ArticleEditViewModel(application: Application) : AndroidViewModel(applicat
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
if (isExit) postArticleDrafts.postValue(true)
Utils.toast(getApplication(), "文章已保存到草稿箱")
if (isExit) {
postArticleDrafts.postValue(true)
Utils.toast(getApplication(), "文章已保存到草稿箱")
}
if (mPostDraftsCount >= AnswerEditActivity.SAVE_DRAFTS_TOAST_COUNT) {
mPostDraftsCount = 0
Utils.toast(getApplication(), "文章已保存到草稿箱")
} else {
mPostDraftsCount++
}
val string = response?.string()
if (!string.isNullOrEmpty() && draftEntity?.id == null) {

View File

@ -19,7 +19,7 @@ class CommentActivity : AppCompatActivity() {
const val SHOW_KEYBOARD = "show_keyboard"
const val ARTICLE_ID = "article_id"
const val ARTICLE_COMMUNITY_ID = "article_community_id"
const val COMMUNITY_ID = "community_id"
const val REQUEST_CODE = 8123
@ -36,13 +36,13 @@ class CommentActivity : AppCompatActivity() {
@JvmStatic
fun getArticleCommentIntent(context: Context, articleId: String, commentCount: Int? = 0,
commentDraft: String? = null, showKeyboard: Boolean,
articleCommunityId: String): Intent {
communityId: String): Intent {
val intent = Intent(context, CommentActivity::class.java)
intent.putExtra(ARTICLE_ID, articleId)
intent.putExtra(COMMENT_COUNT, commentCount)
intent.putExtra(COMMENT_DRAFT, commentDraft)
intent.putExtra(SHOW_KEYBOARD, showKeyboard)
intent.putExtra(ARTICLE_COMMUNITY_ID, articleCommunityId)
intent.putExtra(COMMUNITY_ID, communityId)
return intent
}
}
@ -58,7 +58,7 @@ class CommentActivity : AppCompatActivity() {
val showKeyboard = intent.getBooleanExtra(SHOW_KEYBOARD, false)
val articleId = intent.getStringExtra(ARTICLE_ID)
val articleCommunityId = intent.getStringExtra(ARTICLE_COMMUNITY_ID)
val communityId = intent.getStringExtra(COMMUNITY_ID)
val value = object : AnswerDetailFragment.CommentListener {
override fun onCountChange(count: Int) {
@ -66,7 +66,7 @@ class CommentActivity : AppCompatActivity() {
setResult(Activity.RESULT_OK, resultIntent)
}
override fun onCommentDraftChange(draft: String?) {
override fun onCommentDraftChange(draft: String) {
resultIntent.putExtra(COMMENT_DRAFT, draft)
setResult(Activity.RESULT_OK, resultIntent)
}
@ -82,7 +82,7 @@ class CommentActivity : AppCompatActivity() {
} else {
CommentFragment.getArticleInstance(
articleId,
articleCommunityId,
communityId,
showKeyboard,
commentCount,
commentDraft,

View File

@ -39,7 +39,7 @@ public class CommentConversationFragment extends CommentFragment {
} else {
mEntrance = "(文章-评论详情-查看对话)";
}
mAdapter = new CommentAdapter(getContext(), mArticleId, mArticleCommunityId,
mAdapter = new CommentAdapter(getContext(), mArticleId, mCommunityId,
mAnswerId, false, this, mEntrance);
}
return mAdapter;
@ -52,7 +52,7 @@ public class CommentConversationFragment extends CommentFragment {
mArticleId = getArguments().getString(CommentActivity.ARTICLE_ID);
mArticleCommentId = getArguments().getString(EntranceUtils.KEY_ARTICLE_COMMENT_ID);
mArticleCommunityId = getArguments().getString(CommentActivity.ARTICLE_COMMUNITY_ID);
mCommunityId = getArguments().getString(CommentActivity.COMMUNITY_ID);
mLinkEntity = getArguments().getParcelable(EntranceUtils.KEY_LINK);
super.onCreate(savedInstanceState);
}
@ -88,7 +88,7 @@ public class CommentConversationFragment extends CommentFragment {
@Override
protected CommentViewModel provideListViewModel() {
return ViewModelProviders.of(this, new CommentViewModel.Factory((Application) getContext().getApplicationContext()
, mAnswerId, mCommentId, mArticleId, mArticleCommunityId, mArticleCommentId)).get(CommentViewModel.class);
, mAnswerId, mCommentId, mArticleId, mCommunityId, mArticleCommentId)).get(CommentViewModel.class);
}
@Override

View File

@ -69,7 +69,7 @@ public class CommentFragment extends ListFragment<CommentEntity, CommentViewMode
protected String mAnswerId;
protected String mArticleId;
private String mCommentDraft;
protected String mArticleCommunityId;
protected String mCommunityId;
protected boolean mShowSoftKeyboardOnStartUp;
@ -196,7 +196,7 @@ public class CommentFragment extends ListFragment<CommentEntity, CommentViewMode
@Override
protected CommentViewModel provideListViewModel() {
return ViewModelProviders.of(this, new CommentViewModel.Factory((Application) getContext().getApplicationContext(),
mAnswerId, null, mArticleId, mArticleCommunityId, null)).get(CommentViewModel.class);
mAnswerId, null, mArticleId, mCommunityId, null)).get(CommentViewModel.class);
}
@Override
@ -208,7 +208,7 @@ public class CommentFragment extends ListFragment<CommentEntity, CommentViewMode
} else {
entrance = "(文章详情-评论列表)";
}
mAdapter = new CommentAdapter(getContext(), mArticleId, mArticleCommunityId,
mAdapter = new CommentAdapter(getContext(), mArticleId, mCommunityId,
mAnswerId, true, this, entrance);
}
return mAdapter;
@ -239,7 +239,7 @@ public class CommentFragment extends ListFragment<CommentEntity, CommentViewMode
fragment.mCommentCount = commentCount;
fragment.mCommentListener = listener;
fragment.mCommentDraft = commentDraft;
fragment.mArticleCommunityId = articleCommunityId;
fragment.mCommunityId = articleCommunityId;
return fragment;
}
@ -259,7 +259,9 @@ public class CommentFragment extends ListFragment<CommentEntity, CommentViewMode
String newText = s.toString().substring(0, 140);
mCommentDetailCommentEt.setText(newText);
mCommentDetailCommentEt.setSelection(mCommentDetailCommentEt.getText().length());
Utils.toast(getContext(), "评论不能多于140字");
if (!ClickUtils.isFastDoubleClick(mCommentDetailCommentEt.getId())) {
Utils.toast(getContext(), "评论不能多于140字");
}
}
} else {
mCommentSend.setEnabled(false);

View File

@ -24,4 +24,7 @@ data class AnswerDetailEntity(var content: String = "",
var community: CommunityEntity = CommunityEntity(),
@SerializedName("comment_count")
var commentCount: Int = 0,
var commentable: Boolean? = true,
@SerializedName("next_id")
var nextId: String? = "",
var fold: Boolean? = false) : Parcelable

View File

@ -17,7 +17,8 @@ data class ArticleDetailEntity(@SerializedName("_id")
var user: UserEntity = UserEntity(),
var me: MeEntity = MeEntity(),
val time: ArticleDetailTime = ArticleDetailTime(),
var community: CommunityEntity = CommunityEntity()) : Parcelable
var community: CommunityEntity = CommunityEntity(),
var commentable: Boolean? = true) : Parcelable
@Parcelize
data class ArticleDetailTime(var create: Long = 0, var edit: Long = 0) : Parcelable

View File

@ -14,7 +14,13 @@ data class ArticleEntity(@SerializedName("_id")
val images: List<String> = ArrayList(),
val count: Count = Count(),
val community: CommunityEntity = CommunityEntity(),
val user: UserEntity = UserEntity())
val time: TimeEntity? = TimeEntity(),
val user: UserEntity = UserEntity()) {
data class TimeEntity(var create: Long? = 0,
var update: Long? = 0,
var edit: Long? = 0)
}
@Parcelize
data class Count(

View File

@ -1,24 +0,0 @@
package com.gh.gamecenter.qa.entity
import com.google.gson.annotations.SerializedName
/**
* Created by khy on 18/12/17.
*/
class AskSearchEntity {
@SerializedName("_id")
var id: String = ""
var brief: String = ""
@SerializedName("question")
var questions: Questions = Questions()
var vote: Int = 0
@SerializedName("comment_count")
var commentCount = 0
var images: List<String> = ArrayList()
}

View File

@ -0,0 +1,5 @@
package com.gh.gamecenter.qa.entity
class CommunityHotSearch(val title: String,
val introduction: String,
val keyword: String)

View File

@ -0,0 +1,5 @@
package com.gh.gamecenter.qa.entity
import com.gh.gamecenter.entity.ResultEntity
class CommunityStatusEntity(val isActive: Boolean, val data: ResultEntity?)

View File

@ -15,4 +15,7 @@ data class Questions(@SerializedName("_id")
var communityName: String = "",
@SerializedName("answer_count")
var answerCount: Int = 0,
val time: Long = 0) : Parcelable
var description: String? = null,
var images: List<String> = ArrayList(),
val time: Long = 0,
val count: Count = Count()) : Parcelable

View File

@ -15,6 +15,8 @@ data class QuestionsDetailEntity(var id: String? = null,
var tags: List<String> = ArrayList(),
var title: String? = null,
var description: String? = null,
@SerializedName("related_question")
var relatedQuestion: RelatedQuestion? = null,
var images: List<String> = ArrayList(),
@SerializedName("answer_count")
var answersCount: Int = 0,
@ -36,4 +38,12 @@ data class QuestionsDetailEntity(var id: String? = null,
this.followCount = count
}
@Parcelize
data class RelatedQuestion(
@SerializedName("_id")
var id: String? = "",
var title: String? = "",
@SerializedName("answer_count")
var answerCount: Int? = 0) : Parcelable
}

View File

@ -0,0 +1,21 @@
package com.gh.gamecenter.qa.entity
import com.google.gson.annotations.SerializedName
/**
* Created by khy on 18/12/17.
*/
data class SearchHottestEntity(@SerializedName("_id")
var id: String = "",
var brief: String = "",
var question: Questions = Questions(),
val count: Count = Count(),
var images: List<String> = ArrayList(),
val title: String = "",
val name: String = "",
val icon: String = "",
val description: String = "",
@SerializedName("top_search_type")
val topSearchType: String = "",
val type: String = ""
)

View File

@ -0,0 +1,12 @@
package com.gh.gamecenter.qa.entity
import com.google.gson.annotations.SerializedName
data class SearchNewestEntity(@SerializedName("_id")
var id: String = "",
var brief: String = "",
var title: String = "",
var type: String = "",
var question: Questions = Questions(),
val count: Count = Count(),
var images: List<String> = ArrayList())

View File

@ -7,6 +7,7 @@ import android.view.View
import android.view.ViewGroup
import com.gh.common.constant.ItemViewType
import com.gh.common.util.NewsUtils
import com.gh.common.util.NumberUtils
import com.gh.gamecenter.PersonalHomeActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.adapter.viewholder.FooterViewHolder
@ -59,7 +60,7 @@ class AskFollowAdapter(val context: Context, val viewModel: AskFollowViewModel)
if (historyEntity.foldUsers != null
&& (historyEntity.type == "answer_vote" ||
historyEntity.type == "community_article_vote")) {
val highlightedString = "${historyEntity.foldUsers!!.size}"
val highlightedString = "${NumberUtils.transSimpleCount(historyEntity.foldUsers!!.size)}"
val type = if ("community_article_vote" == historyEntity.type) {
"文章"
} else {

View File

@ -31,7 +31,20 @@ class AskFollowViewModel(application: Application)
}
override fun mergeResultLiveData() {
mResultLiveData.addSource(mListLiveData) { mResultLiveData.postValue(it) }
mResultLiveData.addSource(mListLiveData) { mutableList ->
mutableList?.let {
for (entity in it) {
// 产品说隐藏掉回答和文章在这个页面的评论数,这里简单把它置为 -1 来隐藏
if (entity.type == "answer"
|| entity.type == "community_article"
|| entity.type == "answer_vote"
|| entity.type == "community_article_vote") {
entity.count.comment = -1
}
}
}
mResultLiveData.postValue(mutableList)
}
}
fun getRecommendUser() {

View File

@ -129,7 +129,7 @@ class MyDraftAdapter extends ListAdapter<AnswerEntity> {
, () -> deleteAnswerDraft(answerEntity), null);
});
draftViewHolder.itemView.setOnClickListener(v -> {
mContext.startActivity(AnswerEditActivity.getIntent(mContext,
mContext.startActivity(AnswerEditActivity.Companion.getIntent(mContext,
answerEntity.getQuestions().getId(), answerEntity.getQuestions().getTitle(),
answerEntity.getId(), true, answerEntity.getCommunityName()));
});

View File

@ -9,7 +9,7 @@ import com.gh.gamecenter.baselist.LoadType;
import com.gh.gamecenter.baselist.NormalListViewModel;
import com.gh.gamecenter.eventbus.EBReuse;
import com.gh.gamecenter.manager.UserManager;
import com.gh.gamecenter.qa.answer.edit.AnswerEditFragment;
import com.gh.gamecenter.qa.answer.edit.AnswerEditActivity;
import com.gh.gamecenter.qa.entity.AnswerEntity;
import com.gh.gamecenter.retrofit.RetrofitManager;
@ -48,7 +48,7 @@ public class MyDraftFragment extends ListFragment<AnswerEntity, NormalListViewMo
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(EBReuse reuse) {
if (AnswerEditFragment.ANSWER_DRAFT_CHANGE_TAG.equals(reuse.getType())) {
if (AnswerEditActivity.ANSWER_DRAFT_CHANGE_TAG.equals(reuse.getType())) {
mListRv.scrollToPosition(0);
mBaseHandler.postDelayed(() -> mListViewModel.load(LoadType.REFRESH), 100);
}

View File

@ -109,9 +109,12 @@ public class AnswerViewHolder extends BaseRecyclerViewHolder<AnswerEntity> {
mQuestionTitle.setVisibility(View.VISIBLE);
mQuestionTitle.setText(entity.getQuestions().getTitle());
mVotecount.setText(mVotecount.getContext().getString(R.string.ask_vote_count, NumberUtils.transSimpleCount(entity.getVote())));
mCommentCount.setText(String.format("%s 评论", NumberUtils.transSimpleCount(entity.getCommentCount())));
// 3.6.3 产品说把右下角的社区名字换成时间, 评论隐藏掉
mCommunityName.setVisibility(View.VISIBLE);
mCommunityName.setText(entity.getCommunityName());
mCommunityName.setText(NewsUtils.getFormattedTime(entity.getTime()));
mCommentCount.setVisibility(View.GONE);
// mCommentCount.setText(String.format("%s 评论", NumberUtils.transSimpleCount(entity.getCommentCount())));
// mCommunityName.setText(entity.getCommunityName());
UserEntity user = entity.getUser();
mUsername.setText(user.getName());
ImageUtils.displayIcon(mUsericon, user.getIcon());

View File

@ -181,16 +181,40 @@ public class QuestionsDetailAdapter extends ListAdapter<AnswerEntity> {
private void initQuestionsDetailItemViewHolder(QuestionsDetailItemViewHolder holder) {
List<String> images = mQuestionsDetailEntity.getImages();
if (mQuestionsDetailEntity.getImages().size() == 0) {
holder.mPic2.setVisibility(View.INVISIBLE);
} else if (mQuestionsDetailEntity.getImages().size() == 1) {
holder.mPic2.setVisibility(View.INVISIBLE);
holder.mPic3.setVisibility(View.INVISIBLE);
holder.mPic3Desc.setVisibility(View.GONE);
holder.mPic3Mask.setVisibility(View.GONE);
} else if(mQuestionsDetailEntity.getImages().size() == 2) {
holder.mPic3.setVisibility(View.INVISIBLE);
holder.mPic3Desc.setVisibility(View.GONE);
holder.mPic3Mask.setVisibility(View.GONE);
} else if(mQuestionsDetailEntity.getImages().size() == 3) {
holder.mPic3Desc.setVisibility(View.GONE);
holder.mPic3Mask.setVisibility(View.GONE);
}
for (int i = 0; i < images.size(); i++) {
switch (i) {
case 0:
holder.mPic1.setVisibility(View.VISIBLE);
ImageUtils.display(holder.mPic1, images.get(i));
break;
case 1:
holder.mPic2.setVisibility(View.VISIBLE);
ImageUtils.display(holder.mPic2, images.get(i));
break;
case 2:
holder.mPic3.setVisibility(View.VISIBLE);
ImageUtils.display(holder.mPic3, images.get(i));
if (images.size() > 3) {
holder.mPic3Mask.setVisibility(View.VISIBLE);
holder.mPic3Desc.setVisibility(View.VISIBLE);
holder.mPic3Desc.setText("+" + (images.size() - 3));
}
break;
}
}
@ -236,6 +260,22 @@ public class QuestionsDetailAdapter extends ListAdapter<AnswerEntity> {
holder.concern.setText("关注问题");
}
if (mQuestionsDetailEntity.getRelatedQuestion() != null) {
holder.mRelatedQuestionContainer.setVisibility(View.VISIBLE);
holder.mRelatedQuestionContainer.setOnClickListener(v -> {
mContext.startActivity(QuestionsDetailActivity.getIntent(
mContext,
mQuestionsDetailEntity.getRelatedQuestion().getId(),
mEntrance,
"关联问题"));
});
holder.mRelatedQuestionTitle.setText(mQuestionsDetailEntity.getRelatedQuestion().getTitle());
holder.mRelatedQuestionAnswerCount.setText(
(NumberUtils.transSimpleCount(mQuestionsDetailEntity.getRelatedQuestion().getAnswerCount()) + "回答"));
} else {
holder.mRelatedQuestionContainer.setVisibility(View.GONE);
}
holder.mTitle.setText(mQuestionsDetailEntity.getTitle());
holder.concernCount.setText((NumberUtils.transSimpleCount(mQuestionsDetailEntity.getFollowCount()) + "人关注"));

View File

@ -51,7 +51,6 @@ import com.gh.gamecenter.eventbus.EBReuse;
import com.gh.gamecenter.mvvm.Status;
import com.gh.gamecenter.qa.answer.detail.AnswerDetailActivity;
import com.gh.gamecenter.qa.answer.edit.AnswerEditActivity;
import com.gh.gamecenter.qa.answer.edit.AnswerEditFragment;
import com.gh.gamecenter.qa.answer.fold.AnswerFoldActivity;
import com.gh.gamecenter.qa.entity.AnswerEntity;
import com.gh.gamecenter.qa.entity.Questions;
@ -141,7 +140,7 @@ public class QuestionsDetailFragment
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == QUESTIONS_DETAIL_ANSWER_REQUEST) {
if (resultCode == AnswerEditFragment.SAVE_DRAFTS) {
if (resultCode == AnswerEditActivity.SAVE_DRAFTS) {
postDraftsSuccess();
} else if (resultCode == RESULT_REFRESH) {
onLoadRefresh();
@ -319,7 +318,7 @@ public class QuestionsDetailFragment
mEntrance, "问题详情-答案列表");
startActivityForResult(intent, QUESTIONS_DETAIL_ANSWER_REQUEST);
} else {
startActivityForResult(AnswerEditActivity.getIntent(getContext(), mQuestionsId
startActivityForResult(AnswerEditActivity.Companion.getIntent(getContext(), mQuestionsId
, getQuestionsTitle(), mQuestionsDetailEntity.getCommunity().getName()), QUESTIONS_DETAIL_ANSWER_REQUEST);
}
});
@ -360,7 +359,7 @@ public class QuestionsDetailFragment
case R.id.reuse_nodata_skip:
CheckLoginUtils.checkLogin(getContext(), "问题详情-[我来回答]", () -> {
startActivityForResult(AnswerEditActivity.getIntent(getContext(), mQuestionsId
startActivityForResult(AnswerEditActivity.Companion.getIntent(getContext(), mQuestionsId
, getQuestionsTitle(), mQuestionsDetailEntity.getCommunity().getName()), QUESTIONS_DETAIL_ANSWER_REQUEST);
});
break;

View File

@ -44,6 +44,16 @@ public class QuestionsDetailItemViewHolder extends BaseRecyclerViewHolder {
TextView concern;
@BindView(R.id.questionsdetail_concern_count)
TextView concernCount;
@BindView(R.id.questiondetail_item_pic3_mask)
public View mPic3Mask;
@BindView(R.id.questiondetail_item_pic3_desc)
public TextView mPic3Desc;
@BindView(R.id.questiondetail_related_question_container)
public View mRelatedQuestionContainer;
@BindView(R.id.questiondetail_related_question_title_tv)
public TextView mRelatedQuestionTitle;
@BindView(R.id.questiondetail_related_question_count_tv)
public TextView mRelatedQuestionAnswerCount;
public QuestionsDetailItemViewHolder(View itemView, OnListClickListener listClickListener) {
super(itemView, listClickListener);

View File

@ -17,10 +17,8 @@ import android.widget.EditText
import com.gh.base.BaseActivity
import com.gh.base.fragment.BaseDialogWrapperFragment
import com.gh.base.fragment.WaitingDialogFragment
import com.gh.common.util.DialogUtils
import com.gh.common.util.EntranceUtils
import com.gh.common.util.ErrorHelper
import com.gh.common.util.observeNonNull
import com.gh.common.util.*
import com.gh.common.view.SpacingItemDecoration
import com.gh.gamecenter.R
import com.gh.gamecenter.SuggestionActivity.MEDIA_STORE_REQUEST
import com.gh.gamecenter.databinding.ActivityQuestionsEditBinding
@ -30,6 +28,7 @@ import com.gh.gamecenter.mvvm.Status
import com.gh.gamecenter.qa.entity.QuestionsDetailEntity
import com.gh.gamecenter.qa.questions.edit.pic.QuestionsEditPicAdapter
import com.gh.gamecenter.qa.questions.edit.tip.QuestionTitleTipAdapter
import com.zhihu.matisse.Matisse
import org.json.JSONObject
/**
@ -82,8 +81,10 @@ class QuestionEditActivity : BaseActivity() {
@SuppressLint("Recycle")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (data != null && requestCode == MEDIA_STORE_REQUEST) {
mViewModel.uploadPic(data)
if (requestCode == MEDIA_STORE_REQUEST && resultCode == RESULT_OK) {
val selectedPics = Matisse.obtainResult(data)
mViewModel.validatePic(selectedPics)
}
}
@ -136,9 +137,11 @@ class QuestionEditActivity : BaseActivity() {
val picAdapter = QuestionsEditPicAdapter(this, mViewModel)
mBinding.suggestPicRv.layoutManager = object : GridLayoutManager(this, 5) {
override fun canScrollVertically(): Boolean {
return false
return true
}
}
mBinding.suggestPicRv.addItemDecoration(SpacingItemDecoration(bottom = DisplayUtils.dip2px(10f)))
mBinding.suggestPicRv.adapter = picAdapter
mViewModel.moderatorPostLiveData.observe(this, Observer {
@ -184,6 +187,7 @@ class QuestionEditActivity : BaseActivity() {
, "图片正在上传中,确定取消吗?"
, "确定", "取消", {
mViewModel.uploadImageSubscription!!.dispose()
mViewModel.successfullyUploadedPicList.clear()
mUploadImageCancelDialog?.dismiss()
mProcessingDialog?.dismiss()
}, null)
@ -204,7 +208,7 @@ class QuestionEditActivity : BaseActivity() {
})
mViewModel.picList.observe(this, Observer { it ->
if (it != null) picAdapter.notifyPicList(it)
it?.let { picAdapter.notifyPicList(it) }
})
mViewModel.error.observeNonNull(this) {
@ -213,9 +217,7 @@ class QuestionEditActivity : BaseActivity() {
// 增加提问时, 如果searchKey不为空 光标跳到最后
mBaseHandler.postDelayed({
if (mViewModel.questionEntity == null) {
mBinding.questionseditTitle.setSelection(mBinding.questionseditTitle.text.toString().length)
}
mBinding.questionseditTitle.setSelection(mBinding.questionseditTitle.text.toString().length)
}, 50)
}
@ -229,7 +231,7 @@ class QuestionEditActivity : BaseActivity() {
if (mViewModel.questionEntity?.me?.moderatorLevel == MeEntity.MODERATOR_LEVEL_PRIMARY)
"你的操作将提交给小编审核,确定提交吗?" else "你的操作将立即生效,确定提交吗?(你的管理权限为:高级)",
"确定", "取消", DialogUtils.ConfirmListener {
mViewModel.moderatorsPatchQuestion(false)
mViewModel.uploadPicAndPatchQuestion(false)
}, null)
}
} else {
@ -238,6 +240,11 @@ class QuestionEditActivity : BaseActivity() {
return false
}
override fun onDestroy() {
super.onDestroy()
mProcessingDialog?.dismissAllowingStateLoss()
mProcessingDialog == null
}
// Limits of EditText
private inner class LimitTextWatcher(private val mEditText: EditText) : TextWatcher {
@ -260,7 +267,9 @@ class QuestionEditActivity : BaseActivity() {
val newText = s.toString().substring(0, QuestionEditViewModel.QUESTION_TITLE_MAX_LENGTH)
mBinding.questionseditTitle.setText(newText)
mBinding.questionseditTitle.setSelection(mBinding.questionseditTitle.text?.length!!)
toast("标题最多${QuestionEditViewModel.QUESTION_TITLE_MAX_LENGTH}个字")
mBinding.questionseditTitle.debounceActionWithInterval(2000L) {
toast("标题最多${QuestionEditViewModel.QUESTION_TITLE_MAX_LENGTH}个字")
}
}
} else if (mEditText === mBinding.questionseditContent) {
@ -270,7 +279,9 @@ class QuestionEditActivity : BaseActivity() {
val newText = s.toString().substring(0, QuestionEditViewModel.QUESTION_CONTENT_MAX_LENGTH)
mBinding.questionseditContent.setText(newText)
mBinding.questionseditContent.setSelection(mBinding.questionseditContent.text.length)
toast("内容最多${QuestionEditViewModel.QUESTION_CONTENT_MAX_LENGTH}个字")
mBinding.questionseditContent.debounceActionWithInterval(2000L) {
toast("内容最多${QuestionEditViewModel.QUESTION_CONTENT_MAX_LENGTH}个字")
}
}
}
}

View File

@ -4,7 +4,7 @@ import android.app.Application
import android.arch.lifecycle.AndroidViewModel
import android.arch.lifecycle.MediatorLiveData
import android.arch.lifecycle.MutableLiveData
import android.content.Intent
import android.net.Uri
import android.provider.MediaStore
import android.text.TextUtils
import com.gh.base.fragment.WaitingDialogFragment
@ -33,13 +33,6 @@ import java.io.File
* Created by khy on 28/04/18.
*/
class QuestionEditViewModel(application: Application) : AndroidViewModel(application) {
companion object {
const val QUESTION_TAG_MAX_COUNT = 5
const val PIC_MAX_AMOUNT = 3
const val QUESTION_TITLE_MIN_LENGTH = 6
const val QUESTION_CONTENT_MAX_LENGTH = 300
const val QUESTION_TITLE_MAX_LENGTH = 50
}
private val mApiService: ApiService = RetrofitManager.getInstance(getApplication()).api
@ -59,11 +52,18 @@ class QuestionEditViewModel(application: Application) : AndroidViewModel(applica
// post data
var title: String? = ""
var content: String? = ""
// picList 纯粹用于展示,可以包含本地和网络地址的图片
val picList = MediatorLiveData<MutableList<String>>()
var defaultTags: MutableList<String> = ArrayList()
var questionEntity: QuestionsDetailEntity? = null
val selectedTags: MutableList<String> = ArrayList()
// 以 HTTP 开头的图片列表,即最终提交给接口的 url 列表
var successfullyUploadedPicList = arrayListOf<String>()
// Key 是本地 uri, Value 是 http url 用于判断该图片是否已上传
var picMap = hashMapOf<String, String>()
/**
* 获取默认标签和确定当前communityId
*/
@ -168,70 +168,149 @@ class QuestionEditViewModel(application: Application) : AndroidViewModel(applica
}
/**
* 检查图片是否符合规则并上传图片
* @param picPath 图片本地路径
* 检查图片是否符合规则
*/
fun uploadPic(data: Intent) {
val selectedImage = data.data ?: return
val filePathColumn = arrayOf(MediaStore.Images.Media.DATA)
fun validatePic(picUriList: MutableList<Uri>) {
val pics = picList.value ?: arrayListOf()
for (picUri in picUriList) {
val filePathColumn = arrayOf(MediaStore.Images.Media.DATA)
val application: Application = getApplication()
val application: Application = getApplication()
val cursor = application.contentResolver.query(selectedImage, filePathColumn, null, null, null)
?: return
cursor.moveToFirst()
val cursor = application.contentResolver.query(picUri, filePathColumn, null, null, null)
?: return
cursor.moveToFirst()
val columnIndex = cursor.getColumnIndex(filePathColumn[0])
val picPath = cursor.getString(columnIndex)
cursor.close()
val columnIndex = cursor.getColumnIndex(filePathColumn[0])
val picPath = cursor.getString(columnIndex)
cursor.close()
val file = File(picPath)
if (file.length() > ImageUtils.getUploadFileMaxSize()) {
val maxSize = ImageUtils.getUploadFileMaxSize() / 1024 / 1024
Utils.toast(getApplication(), "不能选择大于${maxSize}MB的图片")
continue
}
Utils.log("picturePath = " + picPath)
val file = File(picPath)
if (file.length() > ImageUtils.getUploadFileMaxSize()) {
val count = ImageUtils.getUploadFileMaxSize() / 1024 / 1024
Utils.toast(getApplication(), getApplication<Application>().getString(R.string.pic_max_hint, count))
return
} else {
val picList = picList.value
if (picList != null && picList.size >= PIC_MAX_AMOUNT) {
Utils.toast(getApplication(), R.string.questions_edit_maxpic_hint)
return
break
}
if (pics.contains(picPath)) {
Utils.toast(getApplication(), "请不要重复上传图片")
} else {
val alreadyUploaded = picMap[picPath]?.isNotEmpty() ?: false
if (alreadyUploaded) {
pics.add(picMap[picPath]!!)
} else {
picMap[picPath] = ""
pics.add(picPath)
}
}
}
picList.postValue(pics)
}
fun uploadPicAndPostQuestion() {
// 先将已上传的图片归类到 successfullyUploadedPicList 里去
picList.value?.let {
for (imageUri in it) {
if (imageUri.startsWith("http") && !successfullyUploadedPicList.contains(imageUri)) {
successfullyUploadedPicList.add(imageUri)
}
}
}
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("上传中...", true))
uploadImageSubscription = UploadImageUtils.compressAndUploadImage(UploadImageUtils.UploadType.question
, picPath, true, object : UploadImageUtils.OnUploadImageListener {
override fun onProgress(total: Long, progress: Long) {
var percent = (100 * (progress / total.toFloat())).toInt()
if (percent >= 100) percent = 99
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("图片上传中 $percent%", true))
}
val picToUpload = findPicToUpload()
if (picToUpload == null) {
postQuestion()
} else {
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("正在准备上传图片...", true))
uploadPic(picToUpload) { postQuestion() }
}
}
override fun onSuccess(imageUrl: String) {
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("上传中...", false))
val list = picList.value ?: ArrayList()
list.add(imageUrl)
picList.postValue(list)
}
override fun onError(e: Throwable?) {
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("上传中...", false))
if (e != null && e is HttpException && e.code() == 403) {
Utils.toast(getApplication(), "图片违规")
} else {
Utils.toast(getApplication(), "图片上传失败,请检查网络")
fun uploadPicAndPatchQuestion(isPatchTags: Boolean) {
// 先将已上传的图片归类到 successfullyUploadedPicList 里去
picList.value?.let {
for (imageUri in it) {
if (imageUri.startsWith("http") && !successfullyUploadedPicList.contains(imageUri)) {
successfullyUploadedPicList.add(imageUri)
}
}
})
}
val picToUpload = findPicToUpload()
if (picToUpload == null) {
moderatorsPatchQuestion(isPatchTags)
} else {
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("正在准备上传图片...", true))
uploadPic(picToUpload) { moderatorsPatchQuestion(isPatchTags) }
}
}
/**
* 移除以上传图片
* @param picPath 图片成功上传后的URL
* 上传图片
*/
fun uploadPic(uri: String, successfulAction: (() -> Unit)? = null) {
picList.value?.let {
uploadImageSubscription = UploadImageUtils.compressAndUploadImage(UploadImageUtils.UploadType.question,
uri,
true,
object : UploadImageUtils.OnUploadImageListener {
override fun onProgress(total: Long, progress: Long) {
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("正在上传图片(${successfullyUploadedPicList.size} / ${it.size}", true))
}
override fun onSuccess(imageUrl: String) {
successfullyUploadedPicList.add(imageUrl)
picMap[uri] = imageUrl
if (successfullyUploadedPicList.size == it.size) {
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("正在上传图片(${successfullyUploadedPicList.size} / ${it.size}", false))
successfulAction?.invoke()
} else {
uploadPic(findPicToUpload()!!, successfulAction)
}
}
override fun onError(e: Throwable?) {
successfullyUploadedPicList.clear()
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("上传中...", false))
if (e != null && e is HttpException && e.code() == 403) {
Utils.toast(getApplication(), "图片违规")
} else {
Utils.toast(getApplication(), "图片上传失败,请检查网络")
}
}
})
}
}
private fun findPicToUpload(): String? {
val list = picList.value
if (list == null) {
return null
} else {
for (uri in list) {
if (!uri.startsWith("http") && picMap[uri].isNullOrEmpty()) {
return uri
}
}
return null
}
}
/**
* 移除已选中图片
*/
fun removePic(picPath: String) {
val list = picList.value
successfullyUploadedPicList.remove(picMap[picPath])
if (list != null && list.remove(picPath)) {
picList.postValue(list)
}
@ -245,11 +324,7 @@ class QuestionEditViewModel(application: Application) : AndroidViewModel(applica
entity.title = title
entity.description = content
entity.tags = selectedTags
entity.images = if (picList.value != null) {
picList.value!!
} else {
ArrayList()
}
entity.images = successfullyUploadedPicList
val body = RequestBody.create(MediaType.parse("application/json"), GsonUtils.toJson(entity))
val observable = if (questionEntity != null) {
@ -292,11 +367,7 @@ class QuestionEditViewModel(application: Application) : AndroidViewModel(applica
val entity = QuestionsDetailEntity()
entity.title = title
entity.description = content
entity.images = if (picList.value != null) {
picList.value!!
} else {
ArrayList()
}
entity.images = successfullyUploadedPicList
GsonUtils.toJson(entity)
}
@ -310,11 +381,7 @@ class QuestionEditViewModel(application: Application) : AndroidViewModel(applica
if (questionEntity?.me?.moderatorLevel == MeEntity.MODERATOR_LEVEL_SUPPER && !isPatchTags) {
questionEntity?.title = title
questionEntity?.description = content
questionEntity?.images = if (picList.value != null) {
picList.value!!
} else {
ArrayList()
}
questionEntity?.images = successfullyUploadedPicList
}
moderatorPostLiveData.postValue(Resource.success(""))
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("提交中...", false))
@ -352,4 +419,13 @@ class QuestionEditViewModel(application: Application) : AndroidViewModel(applica
}
return true
}
companion object {
const val QUESTION_TAG_MAX_COUNT = 5
const val PIC_MAX_AMOUNT = 30
const val QUESTION_TITLE_MIN_LENGTH = 6
const val QUESTION_CONTENT_MAX_LENGTH = 300
const val QUESTION_TITLE_MAX_LENGTH = 50
}
}

View File

@ -161,11 +161,11 @@ class TagsSelectFragment : BaseFragment<String>() {
if (mViewModel?.questionEntity?.me?.moderatorLevel == MeEntity.MODERATOR_LEVEL_PRIMARY)
"你的操作将提交给小编审核,确定提交吗?" else "你的操作将立即生效,确定提交吗?(你的管理权限为:高级)",
"确定", "取消", DialogUtils.ConfirmListener {
mViewModel?.moderatorsPatchQuestion(true)
mViewModel?.uploadPicAndPatchQuestion(true)
}, null)
}
} else {
mViewModel?.postQuestion()
mViewModel?.uploadPicAndPostQuestion()
}
}
}

View File

@ -2,8 +2,8 @@ package com.gh.gamecenter.qa.questions.edit.pic
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.provider.MediaStore
import android.content.pm.ActivityInfo
import android.net.Uri
import android.support.v7.widget.RecyclerView
import android.view.View
import android.view.ViewGroup
@ -13,7 +13,10 @@ import com.gh.gamecenter.SuggestionActivity.MEDIA_STORE_REQUEST
import com.gh.gamecenter.qa.questions.edit.QuestionEditViewModel
import com.gh.gamecenter.suggest.SuggestPicViewHolder
import com.lightgame.adapter.BaseRecyclerAdapter
import com.lightgame.utils.Utils
import com.zhihu.matisse.Matisse
import com.zhihu.matisse.MimeType
import com.zhihu.matisse.engine.impl.PicassoEngine
import java.io.File
import java.util.*
/**
@ -33,11 +36,16 @@ class QuestionsEditPicAdapter(context: Context, viewModel: QuestionEditViewModel
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is SuggestPicViewHolder) {
if (position == itemCount - 1 && picList.size < QuestionEditViewModel.PIC_MAX_AMOUNT) {
holder.delate.visibility = View.GONE
holder.delete.visibility = View.GONE
ImageUtils.display(holder.icon, R.drawable.suggest_add_pic_icon)
} else {
holder.icon.setImageURI(picList[position])
holder.delate.visibility = View.VISIBLE
val picUrl = picList[position]
if (picUrl.startsWith("http")) {
holder.icon.setImageURI(picUrl)
} else {
holder.icon.setImageURI(Uri.fromFile(File((picUrl))))
}
holder.delete.visibility = View.VISIBLE
}
holder.itemView.setOnClickListener {
@ -46,7 +54,7 @@ class QuestionsEditPicAdapter(context: Context, viewModel: QuestionEditViewModel
&& picList.size < QuestionEditViewModel.PIC_MAX_AMOUNT
&& mContext is Activity) {
if (NetworkUtils.isWifiOr4GOr3GConnected(mContext) || mAgreePostPic) {
addPic(mContext as Activity)
selectPic(mContext as Activity)
} else {
mAgreePostPic = true
MtaHelper.onEvent("发表问题", "上传图片-移动网络提示", mViewModel.communityName)
@ -55,26 +63,27 @@ class QuestionsEditPicAdapter(context: Context, viewModel: QuestionEditViewModel
"当前使用移动网络,上传图片会消耗手机流量",
"我知道了", "",
DialogUtils.ConfirmListener {
addPic(mContext as Activity)
selectPic(mContext as Activity)
}, null)
}
}
}
holder.delate.setOnClickListener {
holder.delete.setOnClickListener {
mViewModel.removePic(picList[position])
}
}
}
private fun addPic(activity: Activity) {
try {
val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
activity.startActivityForResult(intent, MEDIA_STORE_REQUEST)
} catch (e: Exception) {
Utils.toast(mContext, R.string.media_image_hint)
e.printStackTrace()
}
private fun selectPic(activity: Activity) {
Matisse.from(activity)
.choose(MimeType.ofImage())
.countable(true)
.maxSelectable(10)
.restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
.thumbnailScale(0.85f)
.imageEngine(PicassoEngine())
.forResult(MEDIA_STORE_REQUEST)
}
override fun getItemCount(): Int {

View File

@ -17,11 +17,13 @@ import android.widget.TextView;
import com.gh.common.util.EntranceUtils;
import com.gh.common.util.ShareUtils;
import com.gh.common.util.TextHelper;
import com.gh.gamecenter.R;
import com.gh.gamecenter.manager.UserManager;
import com.gh.gamecenter.normal.NormalFragment;
import com.gh.gamecenter.qa.entity.QuestionsDetailEntity;
import com.lightgame.utils.Util_System_Keyboard;
import com.lightgame.utils.Utils;
import butterknife.BindView;
import butterknife.OnClick;
@ -112,6 +114,10 @@ public class QuestionsInviteWrapperFragment extends NormalFragment {
mInviteEtSearch.setHint("搜索光环用户");
TextHelper.limitTheLengthOfEditText(mInviteEtSearch, 12, () -> {
Utils.toast(mInviteEtSearch.getContext(), "最多输入12个字");
});
mInviteEtSearch.setOnEditorActionListener((v, actionId, event) -> {
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
mInviteTvSearch.performClick();

View File

@ -59,6 +59,9 @@ public class AskQuestionsRecommendsViewHolder extends BaseRecyclerViewHolder<Ans
public void initQuestionsHotViewHolder(Context context, AnswerEntity entity, String entrance, String path) {
setClickData(entity);
mAskVotecount.setText(itemView.getContext().getString(R.string.ask_vote_count, NumberUtils.transSimpleCount(entity.getVote())));
// 3.6.3 产品说隐藏掉评论
mAskAnswerCount.setVisibility(View.GONE);
mAskAnswerCount.setText(String.format("%s 评论", NumberUtils.transSimpleCount(entity.getCommentCount())));
mAskContent.setText(entity.getBrief());

View File

@ -5,6 +5,7 @@ import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Message;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.text.Editable;
@ -20,6 +21,7 @@ import com.gh.base.BaseActivity;
import com.gh.common.util.CheckLoginUtils;
import com.gh.common.util.EntranceUtils;
import com.gh.common.util.LogUtils;
import com.gh.common.util.MtaHelper;
import com.gh.common.util.TextHelper;
import com.gh.gamecenter.R;
import com.gh.gamecenter.db.AskSearchHistoryDao;
@ -27,16 +29,22 @@ import com.gh.gamecenter.eventbus.EBSearch;
import com.gh.gamecenter.manager.UserManager;
import com.gh.gamecenter.qa.questions.edit.QuestionEditActivity;
import com.gh.gamecenter.qa.search.history.HistoryFragment;
import com.gh.gamecenter.retrofit.Response;
import com.gh.gamecenter.retrofit.RetrofitManager;
import com.lightgame.utils.Util_System_Keyboard;
import com.lightgame.utils.Utils;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.json.JSONArray;
import java.util.List;
import butterknife.BindView;
import butterknife.OnClick;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.ResponseBody;
/**
* Created by khy on 8/12/17.
@ -46,7 +54,7 @@ public class AskSearchActivity extends BaseActivity {
private static final int POST_SEARCH_WHAT = 2;
private static final int QUESTION_REQUEST_CODE = 2;
private static final String ASK_SEARCH_EB_TYPE = "askHistory";
public static final String ASK_SEARCH_EB_TYPE = "invoke_search";
@BindView(R.id.bar_search_edit)
EditText mSearchEt;
@ -63,9 +71,9 @@ public class AskSearchActivity extends BaseActivity {
private String mSearchKey;
private String mPostedKey;
private String mColumnId;
private String mQuestionTag;
private String mDefaultSearchKey;
public static Intent getIntent(Context context, String entrance) {
Intent intent = new Intent(context, AskSearchActivity.class);
@ -123,6 +131,8 @@ public class AskSearchActivity extends BaseActivity {
} else {
mSearchEt.setHint("标签内搜索");
}
} else {
getCommunityDefaultSearch();
}
changeFragment();
@ -176,28 +186,48 @@ public class AskSearchActivity extends BaseActivity {
startActivityForResult(QuestionEditActivity.Companion.getIntent(this, mSearchKey), QUESTION_REQUEST_CODE);
});
} else if (v.getId() == R.id.bar_question_btn) {
if (!TextUtils.isEmpty(mColumnId) || !TextUtils.isEmpty(mQuestionTag)) {
search();
mDao.add(mSearchKey, UserManager.getInstance().getCommunity().getId());
Util_System_Keyboard.hideSoftKeyboard(this, mSearchEt);
} else {
String entrance;
if (!TextUtils.isEmpty(mColumnId)) {
entrance = "专栏详情-搜索-点我提问";
} else if (!TextUtils.isEmpty(mQuestionTag)) {
entrance = "问题标签详情-搜索-点我提问";
} else {
entrance = "问答-搜索-点我提问";
String key = mSearchEt.getText().toString().trim();
if (TextUtils.isEmpty(key)) {
if (!TextUtils.isEmpty(mDefaultSearchKey)) {
mSearchEt.setText(mDefaultSearchKey);
mSearchEt.setSelection(mSearchEt.getText().length());
mDao.add(mDefaultSearchKey, UserManager.getInstance().getCommunity().getId());
Util_System_Keyboard.hideSoftKeyboard(this, mSearchEt);
MtaHelper.onEvent("社区搜索事件", "默认搜索", UserManager.getInstance().getCommunity().getName() + "-" + mDefaultSearchKey);
}
CheckLoginUtils.checkLogin(this, entrance, () -> {
startActivityForResult(QuestionEditActivity.Companion.getIntent(this, mSearchKey), QUESTION_REQUEST_CODE);
});
} else {
mDao.add(mSearchKey, UserManager.getInstance().getCommunity().getId());
MtaHelper.onEvent("社区搜索事件", "主动搜索", UserManager.getInstance().getCommunity().getName() + "-" + mSearchKey);
}
} else if (v.getId() == R.id.bar_back) {
finish();
}
}
private void getCommunityDefaultSearch() {
RetrofitManager
.getInstance(this)
.getApi()
.getCommunityDefaultSearch(UserManager.getInstance().getCommunity().getId())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<ResponseBody>() {
@Override
public void onResponse(@Nullable ResponseBody response) {
try {
JSONArray array = new JSONArray(response.string());
if (array.length() > 0) {
mDefaultSearchKey = (String) array.get(0);
mSearchEt.setHint(mDefaultSearchKey);
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
private void search() {
if (mSearchKey == null) return;
@ -211,6 +241,11 @@ public class AskSearchActivity extends BaseActivity {
postLog(true);
}
public void visibleOrGoneSearchHint(int visibility) {
mSearchHint.setVisibility(visibility);
mSearchShadow.setVisibility(visibility);
}
@Override
public void onDestroy() {
if (TextUtils.isEmpty(mPostedKey) || !mPostedKey.equals(mSearchKey)) {

View File

@ -1,13 +1,20 @@
package com.gh.gamecenter.qa.search;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.text.TextUtils;
import android.view.View;
import com.gh.base.fragment.BaseFragment_TabLayout;
import com.gh.common.util.EntranceUtils;
import com.gh.gamecenter.R;
import com.gh.gamecenter.qa.search.artilce.ArticleFragment;
import com.gh.gamecenter.qa.search.hottest.HottestFragment;
import com.gh.gamecenter.qa.search.newest.NewestFragment;
import com.gh.gamecenter.qa.search.question.QuestionFragment;
import com.gh.gamecenter.qa.search.user.UserFragment;
import java.util.List;
@ -18,20 +25,63 @@ public class AskSearchFragment extends BaseFragment_TabLayout {
@BindView(R.id.fragment_tab_container)
public View mTabContainer;
private String mQuestionTag;
private String mColumnId;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
Bundle arguments = getArguments();
if (arguments != null) {
mQuestionTag = arguments.getString(EntranceUtils.KEY_QUESTION_TAG);
mColumnId = arguments.getString(EntranceUtils.KEY_COLUMN_ID);
}
super.onCreate(savedInstanceState);
}
@Override
protected void initFragmentList(List<Fragment> fragments) {
fragments.add(new HottestFragment());
fragments.add(new NewestFragment());
if (TextUtils.isEmpty(mQuestionTag) && TextUtils.isEmpty(mColumnId)) {
fragments.add(new ArticleFragment());
}
fragments.add(new QuestionFragment());
if (TextUtils.isEmpty(mQuestionTag) && TextUtils.isEmpty(mColumnId)) {
fragments.add(new UserFragment());
}
Bundle arguments = getArguments();
for (Fragment fragment : mFragmentsList) {
fragment.setArguments(getArguments());
fragment.setArguments(arguments);
}
}
@Override
protected void initTabTitleList(List<String> tabTitleList) {
tabTitleList.add("最热回答");
tabTitleList.add("新回答");
tabTitleList.add("只看问题");
if (TextUtils.isEmpty(mQuestionTag) && TextUtils.isEmpty(mColumnId)) {
tabTitleList.add("");
tabTitleList.add("最新");
tabTitleList.add("文章");
tabTitleList.add("问题");
tabTitleList.add("用户");
} else {
tabTitleList.add("最热回答");
tabTitleList.add("最新回答");
tabTitleList.add("只看问题");
}
}
@Override
public void onPageSelected(int position) {
FragmentActivity activity = getActivity();
if (mFragmentsList.get(position) instanceof UserFragment) {
if (activity instanceof AskSearchActivity) {
((AskSearchActivity) activity).visibleOrGoneSearchHint(View.GONE);
}
} else {
if (activity instanceof AskSearchActivity) {
((AskSearchActivity) activity).visibleOrGoneSearchHint(View.VISIBLE);
}
}
}
}

View File

@ -5,9 +5,8 @@ import android.widget.TextView;
import com.facebook.drawee.view.SimpleDraweeView;
import com.gh.base.BaseRecyclerViewHolder;
import com.gh.base.OnListClickListener;
import com.gh.gamecenter.R;
import com.gh.gamecenter.qa.entity.AskSearchEntity;
import com.gh.gamecenter.qa.entity.SearchHottestEntity;
import butterknife.BindView;
@ -15,25 +14,20 @@ import butterknife.BindView;
* Created by khy on 8/12/17.
*/
public class AskSearchNormalItemViewHolder extends BaseRecyclerViewHolder<AskSearchEntity> {
public class AskSearchNormalItemViewHolder extends BaseRecyclerViewHolder<SearchHottestEntity> {
@BindView(R.id.ask_search_item_title)
public TextView mTitle;
@BindView(R.id.ask_search_item_content)
public TextView mContent;
@BindView(R.id.ask_search_item_commentcount)
public TextView mCommentCount;
@BindView(R.id.ask_search_item_answercount)
public TextView mAnswerCount;
@BindView(R.id.ask_search_item_image)
public SimpleDraweeView mImage;
@BindView(R.id.ask_search_item_votecount)
public TextView mVoteCount;
public AskSearchNormalItemViewHolder(View itemView, OnListClickListener listClickListener) {
super(itemView, listClickListener);
itemView.setOnClickListener(this);
mContent.setOnClickListener(this);
}
@BindView(R.id.ask_search_item_top)
public View mTopIcon;
public AskSearchNormalItemViewHolder(View itemView) {
super(itemView);

Some files were not shown because too many files have changed in this diff Show More