diff --git a/app/build.gradle b/app/build.gradle
index ed911266c7..c9177790e5 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -45,6 +45,9 @@ android {
abiFilters "armeabi-v7a"
}
+ renderscriptTargetApi 18
+ renderscriptSupportModeEnabled true
+
// 由于app只针对中文用户,所以仅保留zh资源,其他删掉
resConfigs "zh"
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index d9cfe052ff..c63abfff70 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -562,6 +562,23 @@
android:name=".video.label.VideoLabelActivity"
android:screenOrientation="portrait" />
+
+
+
+
+
+
+
+
w || height > h) {
// 缩放
- scaleWidth = ((float) width) / w;
- scaleHeight = ((float) height) / h;
+ if (w > 0) scaleWidth = ((float) width) / w;
+ if (h > 0) scaleHeight = ((float) height) / h;
}
options.inJustDecodeBounds = false;
int scale = (int) Math.ceil(Math.max(scaleWidth, scaleHeight));
@@ -189,6 +206,7 @@ public class BitmapUtils {
/**
* Drawable转Bitmap
+ *
* @param isSquare 是否是正方形
*/
public static Bitmap drawableToBitmap(Drawable drawable, boolean isSquare) {
@@ -196,7 +214,7 @@ public class BitmapUtils {
return null;
}
- int w,h;
+ int w, h;
// 取 drawable 的长宽
w = drawable.getIntrinsicWidth();
@@ -227,4 +245,108 @@ public class BitmapUtils {
return bitmap;
}
+ /**
+ * 修改bitmap透明度
+ *
+ * @param sourceImg
+ * @param config
+ * @param number
+ * @return
+ */
+ public static Bitmap getTransparentBitmap(Bitmap sourceImg, Bitmap.Config config, int number) {
+ int[] argb = new int[sourceImg.getWidth() * sourceImg.getHeight()];
+ sourceImg.getPixels(argb, 0, sourceImg.getWidth(), 0, 0, sourceImg
+ .getWidth(), sourceImg.getHeight());// 获得图片的ARGB值
+ number = number * 255 / 100;
+ for (int i = 0; i < argb.length; i++) {
+ argb[i] = (number << 24) | (argb[i] & 0x00FFFFFF);
+ }
+ sourceImg = Bitmap.createBitmap(argb, sourceImg.getWidth(), sourceImg
+ .getHeight(), config);
+ return sourceImg;
+ }
+
+
+ /**
+ * 高斯模糊
+ *
+ * @param context
+ * @param image
+ * @param radius
+ * @return
+ */
+ @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
+ public static Bitmap getBlurBitmap(Context context, Bitmap image, @IntRange(from = 1, to = 25) int radius) {
+ // 计算图片缩小后的长宽
+ int width = Math.round(image.getWidth() * 0.8f);
+ int height = Math.round(image.getHeight() * 0.8f);
+
+ // 将缩小后的图片做为预渲染的图片。
+ Bitmap inputBitmap = Bitmap.createScaledBitmap(image, width, height, false);
+ // 创建一张渲染后的输出图片。
+ Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap);
+ // 创建RenderScript内核对象
+ RenderScript rs = RenderScript.create(context);
+ // 创建一个模糊效果的RenderScript的工具对象
+ ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
+
+ // 由于RenderScript并没有使用VM来分配内存,所以需要使用Allocation类来创建和分配内存空间。
+ // 创建Allocation对象的时候其实内存是空的,需要使用copyTo()将数据填充进去。
+ Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap);
+ Allocation tmpOut = Allocation.createTyped(rs, tmpIn.getType());
+ // 设置渲染的模糊程度, 25f是最大模糊度
+ blurScript.setRadius(radius);
+ // 设置blurScript对象的输入内存
+ blurScript.setInput(tmpIn);
+ // 将输出数据保存到输出内存中
+ blurScript.forEach(tmpOut);
+
+ // 将数据填充到Allocation中
+ tmpOut.copyTo(outputBitmap);
+
+ return outputBitmap;
+ }
+
+ /**
+ * 保存图片
+ *
+ * @param bitmap
+ * @param path
+ */
+ public static void saveBitmap(Bitmap bitmap, String path) {
+ File file = new File(path);
+ if (file.exists()) {
+ file.delete();
+ }
+ FileOutputStream out;
+ try {
+ out = new FileOutputStream(file);
+ if (bitmap.compress(Bitmap.CompressFormat.PNG, 80, out)) {
+ out.flush();
+ out.close();
+ }
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ public static Bitmap compressBitmap(Bitmap bitmap) {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ Matrix matrix = new Matrix();
+ Bitmap result = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
+ result.compress(Bitmap.CompressFormat.WEBP, 100, bos);
+
+ while (bos.toByteArray().length > 400 * 1024) {
+ System.out.println(bos.toByteArray().length);
+ matrix.setScale(0.9f, 0.9f);
+ result = Bitmap.createBitmap(result, 0, 0, result.getWidth(), result.getHeight(), matrix, true);
+ bos.reset();
+ result.compress(Bitmap.CompressFormat.WEBP, 100, bos);
+ }
+
+ return result;
+ }
}
diff --git a/app/src/main/java/com/gh/common/util/Extensions.kt b/app/src/main/java/com/gh/common/util/Extensions.kt
index 13ac076f8f..ce1b895f92 100644
--- a/app/src/main/java/com/gh/common/util/Extensions.kt
+++ b/app/src/main/java/com/gh/common/util/Extensions.kt
@@ -15,6 +15,7 @@ import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.PopupWindow
+import android.widget.SeekBar
import android.widget.TextView
import androidx.annotation.ColorRes
import androidx.core.content.ContextCompat
@@ -268,6 +269,7 @@ fun Context.showRegulationTestDialogIfNeeded(action: (() -> Unit)) {
action()
}
}
+
/**
* 在限定 interval 里只触发一次 action
*/
@@ -425,7 +427,7 @@ fun Float.px2dip(): Int {
return (this / scale + 0.5f).toInt()
}
-fun Float.sp2px():Int{
+fun Float.sp2px(): Int {
val scale: Float = HaloApp.getInstance().application.resources.displayMetrics.scaledDensity
return (this * scale + 0.5f).toInt()
}
@@ -818,4 +820,21 @@ fun EditText.showKeyBoard() {
val inputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.showSoftInput(this, 0)
}, 300)
+}
+
+
+fun SeekBar.doOnSeekBarChangeListener(progressChange: ((progress: Int) -> Unit)?=null, onStopTrackingTouch: (() -> Unit)? = null) {
+ this.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
+ override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
+ progressChange?.invoke(progress)
+ }
+
+ override fun onStartTrackingTouch(seekBar: SeekBar?) {
+
+ }
+
+ override fun onStopTrackingTouch(seekBar: SeekBar?) {
+ onStopTrackingTouch?.invoke()
+ }
+ })
}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/common/util/UploadImageUtils.kt b/app/src/main/java/com/gh/common/util/UploadImageUtils.kt
index 7ad0a46793..6672758ea4 100644
--- a/app/src/main/java/com/gh/common/util/UploadImageUtils.kt
+++ b/app/src/main/java/com/gh/common/util/UploadImageUtils.kt
@@ -32,7 +32,8 @@ object UploadImageUtils {
suggestion,
icon,
poster,
- game_upload
+ game_upload,
+ user_background
}
// 不处理图片,只是单纯的上传
@@ -273,11 +274,11 @@ object UploadImageUtils {
}
// 防止GIF图片文件后缀不是GIF,这个FileName只是告诉服务端后缀格式,没有其他用处
- private fun getFileName(file: File): String {
+ fun getFileName(file: File): String {
val options = BitmapFactory.Options()
options.inJustDecodeBounds = true
BitmapFactory.decodeFile(file.absolutePath, options)
- if (options.outMimeType.contains("gif") && !file.name.toLowerCase().contains(".gif".toLowerCase())) {
+ if (options.outMimeType != null && options.outMimeType.contains("gif") && !file.name.toLowerCase().contains(".gif".toLowerCase())) {
return System.currentTimeMillis().toString() + ".gif"
}
return URLEncoder.encode(file.name, "utf-8")
diff --git a/app/src/main/java/com/gh/common/view/AvatarBorderView.kt b/app/src/main/java/com/gh/common/view/AvatarBorderView.kt
new file mode 100644
index 0000000000..a170a59f46
--- /dev/null
+++ b/app/src/main/java/com/gh/common/view/AvatarBorderView.kt
@@ -0,0 +1,115 @@
+package com.gh.common.view
+
+import android.content.Context
+import android.graphics.drawable.ColorDrawable
+import android.util.AttributeSet
+import android.view.View
+import android.widget.RelativeLayout
+import androidx.core.content.ContextCompat
+import com.facebook.drawee.drawable.ScalingUtils
+import com.facebook.drawee.generic.GenericDraweeHierarchy
+import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder
+import com.facebook.drawee.generic.RoundingParams
+import com.facebook.drawee.view.SimpleDraweeView
+import com.gh.common.util.ImageUtils
+import com.gh.common.util.dip2px
+import com.gh.gamecenter.R
+
+
+class AvatarBorderView : RelativeLayout {
+
+ var avatarView: SimpleDraweeView? = null
+ var borderView: SimpleDraweeView? = null
+ private var mAvatarWidth = 100f
+
+ constructor(context: Context) : super(context)
+ constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
+ initView(attrs)
+ }
+
+ constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
+ initView(attrs)
+ }
+
+ private fun initView(attrs: AttributeSet) {
+ val ta = context.obtainStyledAttributes(attrs, R.styleable.AvatarBorderView)
+ if (ta.hasValue(R.styleable.AvatarBorderView_avatar_width)) {
+ mAvatarWidth = ta.getDimension(R.styleable.AvatarBorderView_avatar_width, mAvatarWidth)
+ }
+ ta.recycle()
+
+ avatarView = createAvatarView()
+ addView(avatarView)
+ borderView = createBorderView()
+ addView(borderView)
+ requestLayout()
+ }
+
+ private fun createAvatarView(): SimpleDraweeView {
+ val avatarView = SimpleDraweeView(context)
+ avatarView.hierarchy = getGenericDraweeHierarchy()
+ val params = LayoutParams(mAvatarWidth.toInt(), mAvatarWidth.toInt())
+ params.addRule(CENTER_IN_PARENT)
+ avatarView.layoutParams = params
+ return avatarView
+ }
+
+ private fun createBorderView(): SimpleDraweeView {
+ val borderView = SimpleDraweeView(context)
+ borderView.hierarchy = getGenericBorderDraweeHierarchy()
+ val params = LayoutParams((mAvatarWidth * 3 / 2).toInt(), (mAvatarWidth * 3 / 2).toInt())
+ borderView.layoutParams = params
+ return borderView
+ }
+
+ private fun getGenericDraweeHierarchy(): GenericDraweeHierarchy {
+ val roundingParams = RoundingParams().apply {
+ roundAsCircle = true
+ borderWidth = 2f.dip2px().toFloat()
+ borderColor = ContextCompat.getColor(context, R.color.white)
+ }
+ return GenericDraweeHierarchyBuilder(resources)
+ .setFadeDuration(500)
+ .setRoundingParams(roundingParams)
+ .setPressedStateOverlay(ColorDrawable(ContextCompat.getColor(context, R.color.pressed_bg)))
+ .setPlaceholderImage(R.drawable.occupy2, ScalingUtils.ScaleType.CENTER)
+ .setBackground(ColorDrawable(ContextCompat.getColor(context, R.color.placeholder_bg)))
+ .setActualImageScaleType(ScalingUtils.ScaleType.CENTER_CROP)
+ .build()
+ }
+
+ private fun getGenericBorderDraweeHierarchy(): GenericDraweeHierarchy {
+ val roundingParams = RoundingParams()
+ return GenericDraweeHierarchyBuilder(resources)
+ .setFadeDuration(500)
+ .setRoundingParams(roundingParams)
+ .setPressedStateOverlay(ColorDrawable(ContextCompat.getColor(context, R.color.pressed_bg)))
+ .setPlaceholderImage(R.drawable.occupy2, ScalingUtils.ScaleType.CENTER)
+ .setBackground(ColorDrawable(ContextCompat.getColor(context, R.color.placeholder_bg)))
+ .setActualImageScaleType(ScalingUtils.ScaleType.CENTER_CROP)
+ .build()
+ }
+
+ fun display(borderUrl: String?, avatarUrl: String) {
+ if (!borderUrl.isNullOrEmpty()) {
+ borderView?.visibility = View.VISIBLE
+ ImageUtils.display(borderView, borderUrl)
+ } else {
+ borderView?.visibility = View.INVISIBLE
+ }
+ ImageUtils.display(avatarView, avatarUrl)
+ }
+
+ fun displayAvatar(avatarUrl: String) {
+ ImageUtils.display(avatarView, avatarUrl)
+ }
+
+ fun displayBorder(borderUrl: String?) {
+ if (!borderUrl.isNullOrEmpty()) {
+ borderView?.visibility = View.VISIBLE
+ ImageUtils.display(borderView, borderUrl)
+ } else {
+ borderView?.visibility = View.INVISIBLE
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/common/view/CropImageCustom.java b/app/src/main/java/com/gh/common/view/CropImageCustom.java
index bbdee76a48..6f71eef96b 100644
--- a/app/src/main/java/com/gh/common/view/CropImageCustom.java
+++ b/app/src/main/java/com/gh/common/view/CropImageCustom.java
@@ -1,12 +1,15 @@
package com.gh.common.view;
import android.content.Context;
+import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.ImageView;
import android.widget.RelativeLayout;
+import com.gh.gamecenter.R;
+
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
@@ -37,6 +40,9 @@ public class CropImageCustom extends RelativeLayout {
mHorizontalPadding = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, mHorizontalPadding, getResources()
.getDisplayMetrics());
+ TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CropImageCustom);
+ mHorizontalPadding = (int) ta.getDimension(R.styleable.CropImageCustom_horizontalPadding, mHorizontalPadding);
+ ta.recycle();
mZoomImageView.setHorizontalPadding(mHorizontalPadding, mRatio);
mClipImageView.setHorizontalPadding(mHorizontalPadding, mRatio);
diff --git a/app/src/main/java/com/gh/common/view/CustomSeekBar.kt b/app/src/main/java/com/gh/common/view/CustomSeekBar.kt
new file mode 100644
index 0000000000..70f933584e
--- /dev/null
+++ b/app/src/main/java/com/gh/common/view/CustomSeekBar.kt
@@ -0,0 +1,94 @@
+package com.gh.common.view
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.Rect
+import android.util.AttributeSet
+import android.view.View
+import androidx.appcompat.widget.AppCompatSeekBar
+import com.gh.common.util.DisplayUtils
+import com.gh.common.util.dip2px
+import com.gh.common.util.px2dip
+import com.gh.common.util.sp2px
+import com.gh.gamecenter.R
+
+/**
+ * 自定义滑块顶部带进度显示的SeekBar
+ */
+class CustomSeekBar : AppCompatSeekBar {
+
+ private var mProgressTextColor = Color.parseColor("#2496FF")
+ private var mProgressTextSize = 14f
+ private var mProgressTextPaddingBottom = 10f
+
+ constructor(context: Context) : super(context)
+ constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
+ initView(attrs)
+ }
+
+ constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
+ initView(attrs)
+ }
+
+ private fun initView(attrs: AttributeSet) {
+ val ta = context.obtainStyledAttributes(attrs, R.styleable.CustomSeekBar)
+ mProgressTextColor = ta.getColor(R.styleable.CustomSeekBar_progressTextColor, mProgressTextColor)
+ if (ta.hasValue(R.styleable.CustomSeekBar_progressTextSize)) {
+ mProgressTextSize = ta.getDimension(R.styleable.CustomSeekBar_progressTextSize, mProgressTextSize)
+ mProgressTextSize = DisplayUtils.px2sp(context, mProgressTextSize).toFloat()
+ }
+ if (ta.hasValue(R.styleable.CustomSeekBar_progressTextPaddingBottom)) {
+ mProgressTextPaddingBottom = ta.getDimension(R.styleable.CustomSeekBar_progressTextPaddingBottom, mProgressTextPaddingBottom)
+ mProgressTextPaddingBottom = mProgressTextPaddingBottom.px2dip().toFloat()
+ }
+ ta.recycle()
+ }
+
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+ val thumbHeight = if (thumb == null) 0 else thumb.intrinsicHeight
+ val measureText = measureText("0")
+ val dh = thumbHeight + measureText.second + mProgressTextPaddingBottom.dip2px()
+ setMeasuredDimension(
+ View.getDefaultSize(0, widthMeasureSpec),
+ View.resolveSizeAndState(dh, heightMeasureSpec, 0)
+ )
+ }
+
+ @SuppressLint("DrawAllocation")
+ override fun onDraw(canvas: Canvas?) {
+ canvas?.save()
+ //由于滑块和进度都是居中绘制,所以这里需要向下移动
+ canvas?.translate(0f, mProgressTextPaddingBottom.dip2px().toFloat())
+ super.onDraw(canvas)
+ canvas?.restore()
+
+ val paint = Paint()
+ paint.isAntiAlias = true
+ paint.textSize = mProgressTextSize.sp2px().toFloat()
+ paint.color = mProgressTextColor
+ val textString = "${progress * 100 / max}%"
+ val pair = measureText(textString)
+ val percent = progress.toFloat() / max
+ val progressWidth = width - paddingLeft - paddingRight
+ val offsetX = progressWidth * percent + paddingLeft - pair.first / 2
+ canvas?.drawText(
+ textString,
+ offsetX,
+ pair.second.toFloat() - paint.fontMetrics.descent,
+ paint
+ )
+ }
+
+ private fun measureText(str: String): Pair {
+ val paint = Paint()
+ paint.textSize = mProgressTextSize.sp2px().toFloat()
+ val rect = Rect()
+ paint.getTextBounds(str, 0, str.length, rect)
+ val w: Int = rect.width()
+ val h: Int = rect.height()
+ return Pair(w, h + paint.fontMetrics.descent.toInt())
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/CropImageActivity.java b/app/src/main/java/com/gh/gamecenter/CropImageActivity.java
index 5f48a4c873..09ca79c334 100644
--- a/app/src/main/java/com/gh/gamecenter/CropImageActivity.java
+++ b/app/src/main/java/com/gh/gamecenter/CropImageActivity.java
@@ -10,8 +10,6 @@ import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
-import androidx.annotation.NonNull;
-
import com.gh.base.ToolBarActivity;
import com.gh.common.util.BitmapUtils;
import com.gh.common.util.DisplayUtils;
@@ -21,6 +19,7 @@ import com.gh.common.view.CropImageCustom;
import java.io.File;
import java.lang.ref.SoftReference;
+import androidx.annotation.NonNull;
import butterknife.BindView;
public class CropImageActivity extends ToolBarActivity {
diff --git a/app/src/main/java/com/gh/gamecenter/entity/AvatarBorderEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/AvatarBorderEntity.kt
new file mode 100644
index 0000000000..63ea7ae65d
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/entity/AvatarBorderEntity.kt
@@ -0,0 +1,10 @@
+package com.gh.gamecenter.entity
+
+import com.google.gson.annotations.SerializedName
+
+data class AvatarBorderEntity(
+ @SerializedName("_id")
+ var id: String = "",
+ var url: String = "",
+ var name: String = ""
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/entity/BackgroundImageEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/BackgroundImageEntity.kt
new file mode 100644
index 0000000000..ad20008921
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/entity/BackgroundImageEntity.kt
@@ -0,0 +1,15 @@
+package com.gh.gamecenter.entity
+
+import android.os.Parcelable
+import com.google.gson.annotations.SerializedName
+import kotlinx.android.parcel.Parcelize
+
+@Parcelize
+data class BackgroundImageEntity(
+ @SerializedName("_id")
+ var id: String = "",
+ var url: String = "",
+ var name: String = "",
+ var opacity: Int = 0,
+ var blur: Int = 1
+) : Parcelable
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/entity/UserInfoEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/UserInfoEntity.kt
index e3120663f5..1d2ec0e924 100644
--- a/app/src/main/java/com/gh/gamecenter/entity/UserInfoEntity.kt
+++ b/app/src/main/java/com/gh/gamecenter/entity/UserInfoEntity.kt
@@ -38,4 +38,9 @@ class UserInfoEntity {
@SerializedName("login_mobile")
var loginMobile: String? = null
+
+ var background: BackgroundImageEntity? = null
+
+ @SerializedName("icon_border")
+ var iconBorder: AvatarBorderEntity? = null
}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/forum/follow/ForumMyFollowFragment.kt b/app/src/main/java/com/gh/gamecenter/forum/follow/ForumMyFollowFragment.kt
index 1adb37e836..ef0538645e 100644
--- a/app/src/main/java/com/gh/gamecenter/forum/follow/ForumMyFollowFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/forum/follow/ForumMyFollowFragment.kt
@@ -54,6 +54,9 @@ class ForumMyFollowFragment : NormalFragment() {
mNoConnection.visibility = View.VISIBLE
}
})
+ mNoConnection.setOnClickListener {
+ mViewModel?.loadFollowsForum()
+ }
mRefresh.setOnRefreshListener {
mViewModel?.loadFollowsForum()
}
diff --git a/app/src/main/java/com/gh/gamecenter/personalhome/background/BackgroundClipActivity.kt b/app/src/main/java/com/gh/gamecenter/personalhome/background/BackgroundClipActivity.kt
new file mode 100644
index 0000000000..a43b1b6daa
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/personalhome/background/BackgroundClipActivity.kt
@@ -0,0 +1,85 @@
+package com.gh.gamecenter.personalhome.background
+
+import android.app.Activity
+import android.content.Context
+import android.content.Intent
+import android.graphics.Bitmap
+import android.os.Bundle
+import android.widget.ImageView
+import com.gh.base.BaseActivity
+import com.gh.base.fragment.WaitingDialogFragment
+import com.gh.common.runOnIoThread
+import com.gh.common.util.BitmapUtils
+import com.gh.common.util.DisplayUtils
+import com.gh.common.util.EntranceUtils
+import com.gh.gamecenter.CropImageActivity
+import com.gh.gamecenter.R
+import com.gh.gamecenter.databinding.ActivityBackgroundClipBinding
+import java.io.File
+import java.lang.ref.SoftReference
+
+class BackgroundClipActivity : BaseActivity() {
+
+ private lateinit var mBinding: ActivityBackgroundClipBinding
+ private var reference: SoftReference? = null
+ private var mPostDialog: WaitingDialogFragment? = null
+
+ override fun getLayoutId(): Int = R.layout.activity_background_clip
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ DisplayUtils.transparentStatusBar(this)
+ mBinding = ActivityBackgroundClipBinding.bind(mContentView)
+ mBinding.cropImageIv.setCropRatio(2 / 3F)
+
+ mBinding.cancelTv.setOnClickListener {
+ finish()
+ }
+ mBinding.nextTv.setOnClickListener {
+ mPostDialog = WaitingDialogFragment.newInstance("正在生成预览...")
+ mPostDialog?.show(supportFragmentManager, null)
+ runOnIoThread {
+ val data = Intent()
+ val clipPath = cacheDir.absolutePath + File.separator + System.currentTimeMillis() + ".jpg"
+ mBinding.cropImageIv.savePicture(clipPath)
+
+ data.putExtra(CropImageActivity.RESULT_CLIP_PATH, clipPath)
+ setResult(Activity.RESULT_OK, data)
+ mPostDialog?.dismiss()
+ finish()
+ }
+
+ }
+ }
+
+
+ override fun onWindowFocusChanged(hasFocus: Boolean) {
+ super.onWindowFocusChanged(hasFocus)
+ if (hasFocus && (reference == null || reference?.get() == null)) {
+ val imageView: ImageView = mBinding.cropImageIv.cropImageZoomView
+ val bitmap = BitmapUtils.getBitmapByFile(intent.getStringExtra(EntranceUtils.KEY_PATH),
+ imageView.width, imageView.height)
+ if (bitmap != null) {
+ reference = SoftReference(bitmap)
+ imageView.setImageBitmap(reference?.get())
+ }
+ }
+ }
+
+
+ override fun onDestroy() {
+ super.onDestroy()
+ if (reference != null && reference!!.get() != null) {
+ reference?.get()?.recycle()
+ }
+ }
+
+ companion object {
+ fun getIntent(context: Context, picturePath: String, entrance: String = ""): Intent? {
+ val intent = Intent(context, BackgroundClipActivity::class.java)
+ intent.putExtra(EntranceUtils.KEY_PATH, picturePath)
+ intent.putExtra(EntranceUtils.KEY_ENTRANCE, entrance)
+ return intent
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/personalhome/background/BackgroundPreviewActivity.kt b/app/src/main/java/com/gh/gamecenter/personalhome/background/BackgroundPreviewActivity.kt
new file mode 100644
index 0000000000..d8cc181080
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/personalhome/background/BackgroundPreviewActivity.kt
@@ -0,0 +1,40 @@
+package com.gh.gamecenter.personalhome.background
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import com.gh.base.BaseActivity
+import com.gh.common.util.DisplayUtils
+import com.gh.common.util.EntranceUtils
+import com.gh.gamecenter.NormalActivity
+import com.gh.gamecenter.R
+import com.gh.gamecenter.amway.AmwayFragment
+import com.gh.gamecenter.entity.BackgroundImageEntity
+
+class BackgroundPreviewActivity : BaseActivity() {
+
+ override fun getLayoutId(): Int = R.layout.activity_amway
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ DisplayUtils.transparentStatusBar(this)
+ DisplayUtils.setLightStatusBar(this, true)
+
+ val containerFragment = supportFragmentManager.findFragmentByTag(BackgroundPreviewFragment::class.java.simpleName)
+ ?: BackgroundPreviewFragment().with(intent.extras)
+ // 若 placeholder 外层为 RelativeLayout 的话,会出现莫名的偏移
+ supportFragmentManager.beginTransaction().replace(R.id.placeholder, containerFragment, BackgroundPreviewFragment::class.java.simpleName).commitAllowingStateLoss()
+ }
+
+ companion object {
+ fun getIntent(context: Context, localPath: String, entity: BackgroundImageEntity?): Intent {
+ val intent = Intent(context, BackgroundPreviewActivity::class.java)
+ intent.putExtra(EntranceUtils.KEY_LOCAL_PATH, localPath)
+ if (entity != null) {
+ intent.putExtra(BackgroundImageEntity::class.java.simpleName, entity)
+ }
+ return intent
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/personalhome/background/BackgroundPreviewFragment.kt b/app/src/main/java/com/gh/gamecenter/personalhome/background/BackgroundPreviewFragment.kt
new file mode 100644
index 0000000000..90dcb20890
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/personalhome/background/BackgroundPreviewFragment.kt
@@ -0,0 +1,291 @@
+package com.gh.gamecenter.personalhome.background
+
+import android.annotation.SuppressLint
+import android.app.Activity
+import android.content.Intent
+import android.content.pm.ActivityInfo
+import android.graphics.Bitmap
+import android.os.Build
+import android.os.Bundle
+import android.os.Looper
+import android.view.View
+import android.view.ViewTreeObserver
+import android.view.ViewTreeObserver.*
+import androidx.annotation.RequiresApi
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.core.content.ContextCompat
+import androidx.databinding.DataBindingUtil
+import com.bytedance.sdk.open.aweme.utils.Md5Utils
+import com.gh.base.fragment.WaitingDialogFragment
+import com.gh.common.util.*
+import com.gh.gamecenter.CropImageActivity
+import com.gh.gamecenter.R
+import com.gh.gamecenter.databinding.FragmentBackgroundPreviewBinding
+import com.gh.gamecenter.entity.BackgroundImageEntity
+import com.gh.gamecenter.manager.UserManager
+import com.gh.gamecenter.normal.NormalFragment
+import com.gh.gamecenter.user.UserViewModel
+import com.halo.assistant.HaloApp
+import com.zhihu.matisse.Matisse
+import com.zhihu.matisse.MimeType
+import com.zhihu.matisse.engine.impl.PicassoEngine
+import io.reactivex.Single
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.schedulers.Schedulers
+import java.io.File
+import kotlin.math.roundToInt
+import android.view.ViewTreeObserver.OnGlobalFocusChangeListener as OnGlobalFocusChangeListener
+
+class BackgroundPreviewFragment : NormalFragment() {
+
+ private var mOriginBitmap: Bitmap? = null
+ private var mTempBitmap: Bitmap? = null
+ private lateinit var mBinding: FragmentBackgroundPreviewBinding
+ private var mPostDialog: WaitingDialogFragment? = null
+ private var mLocalPath: String = ""
+ private var backgroundImageEntity: BackgroundImageEntity? = null//如果为空,则是本地选择的
+
+ private lateinit var mUserViewModel: UserViewModel
+
+ override fun getLayoutId(): Int = 0
+
+ override fun getInflatedLayout(): View {
+ mBinding = DataBindingUtil.inflate(layoutInflater, R.layout.fragment_background_preview, null, false)
+ return mBinding.root
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ mUserViewModel = viewModelProvider(UserViewModel.Factory(HaloApp.getInstance().application))
+ mUserViewModel.uploadBackground.observeNonNull(this) {
+ mPostDialog?.dismiss()
+ if (it) {
+ requireActivity().finish()
+ mUserViewModel.uploadBackground.value = false
+ }
+ }
+
+ Looper.myQueue().addIdleHandler {
+ changeBackgroundViewParams()
+ false
+ }
+ }
+
+ private fun changeBackgroundViewParams() {
+ val screenHeight = DisplayUtils.px2dip(requireContext(), DisplayUtils.getScreenHeight().toFloat())
+ val picProportion = if (screenHeight > 640) 6 / 13f else 9 / 16f
+ val width = mBinding.previewMineIv.width
+ val height = mBinding.previewMineIv.height
+ val realHeight = width / picProportion
+
+ val mineGhIvParams = mBinding.personalHomeIv.layoutParams as ConstraintLayout.LayoutParams
+ mineGhIvParams.topMargin = ((height - realHeight) / 2).toInt()
+ mBinding.mineGhIv.layoutParams = mineGhIvParams
+
+ val personalHomeIvParams = mBinding.mineGhIv.layoutParams as ConstraintLayout.LayoutParams
+ personalHomeIvParams.topMargin = ((height - realHeight) / 2).toInt()
+ mBinding.personalHomeIv.layoutParams = personalHomeIvParams
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ mLocalPath = arguments?.getString(EntranceUtils.KEY_LOCAL_PATH) ?: ""
+ backgroundImageEntity = arguments?.getParcelable(BackgroundImageEntity::class.java.simpleName)
+ mOriginBitmap = BitmapUtils.getBitmapByFile(mLocalPath, Bitmap.Config.ARGB_8888)
+ mTempBitmap = Bitmap.createBitmap(mOriginBitmap)
+ mBinding.mineGhIv.setImageBitmap(mOriginBitmap)
+ mBinding.personalHomeIv.setImageBitmap(mOriginBitmap)
+
+ val screenHeight = DisplayUtils.px2dip(requireContext(), DisplayUtils.getScreenHeight().toFloat())
+ if (screenHeight > 640) {
+ mBinding.previewMineIv.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.preview_mine_full))
+ mBinding.previewHomeIv.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.preview_home_full))
+ } else {
+ mBinding.previewMineIv.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.preview_mine))
+ mBinding.previewHomeIv.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.preview_home))
+ }
+
+ mBinding.normalTitle.text = "预览"
+ mBinding.normalToolbar.setNavigationOnClickListener { requireActivity().finish() }
+
+ mBinding.alphaSeek.doOnSeekBarChangeListener({
+ mBinding.mineGhIv.alpha = it / 100f
+ mBinding.personalHomeIv.alpha = it / 100f
+ changeCommitButton()
+ })
+
+ mBinding.blurSeek.doOnSeekBarChangeListener({
+ changeCommitButton()
+ }, {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ changeAmbiguity()
+ } else {
+ ToastUtils.showToast("系统版本太低")
+ }
+ })
+
+ mBinding.changeBackgroundTv.setOnClickListener {
+ if (backgroundImageEntity == null) {
+ selectPic(requireActivity())
+ } else {
+ requireActivity().finish()
+ }
+ }
+
+ mBinding.commitTv.setOnClickListener {
+ PermissionHelper.checkStoragePermissionBeforeAction(requireContext(), object : EmptyCallback {
+ override fun onCallback() {
+ mTempBitmap?.let {
+ val filePath: String = "${requireContext().cacheDir.absolutePath}${File.separator}${Md5Utils.hexDigest(mLocalPath)}.webp"
+ savePicture(filePath, it)
+ }
+ }
+ })
+ }
+
+ val background = UserManager.getInstance().userInfoEntity.background
+ if (backgroundImageEntity != null && backgroundImageEntity!!.id == background?.id) {
+ mBinding.alphaSeek.progress = background.opacity
+ if (background.blur in 1..25 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ mBinding.blurSeek.progress = background.blur
+ changeAmbiguity()
+ }
+ mBinding.commitTv.text = "使用中"
+ }
+ }
+
+ @RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
+ private fun changeAmbiguity() {
+ var progress = mBinding.blurSeek.progress
+ mTempBitmap = if (progress == 0) {
+ Bitmap.createBitmap(mOriginBitmap)
+ } else {
+ BitmapUtils.getBlurBitmap(requireContext(), mOriginBitmap, progress)
+ }
+ mBinding.mineGhIv.setImageBitmap(mTempBitmap)
+ mBinding.personalHomeIv.setImageBitmap(mTempBitmap)
+ }
+
+ private fun changeCommitButton() {
+ val background = UserManager.getInstance().userInfoEntity.background
+ if (backgroundImageEntity != null && backgroundImageEntity!!.id == background?.id) {
+ if (mBinding.alphaSeek.progress != background.opacity || mBinding.blurSeek.progress != background.blur) {
+ mBinding.commitTv.text = "使用"
+ mBinding.commitTv.isEnabled = true
+ } else {
+ mBinding.commitTv.isEnabled = false
+ mBinding.commitTv.text = "使用中"
+ }
+ }
+ }
+
+ @SuppressLint("CheckResult")
+ private fun savePicture(path: String, bitmap: Bitmap) {
+ mPostDialog = WaitingDialogFragment.newInstance("加载中...")
+ mPostDialog?.show(childFragmentManager, null)
+ Single.just(bitmap)
+ .map {
+ if (mBinding.alphaSeek.progress == 100) {
+ it
+ } else {
+ BitmapUtils.getTransparentBitmap(bitmap, Bitmap.Config.ARGB_8888, mBinding.alphaSeek.progress)
+ }
+ }
+ .map {
+ BitmapUtils.compressBitmap(it)
+ }
+ .map {
+ BitmapUtils.saveBitmap(it, path)
+ path
+ }
+ .flatMap {
+ uploadImage(it)
+ }
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe({
+ mPostDialog?.dismiss()
+ val entity = BackgroundImageEntity(backgroundImageEntity?.id
+ ?: "", it, opacity = mBinding.alphaSeek.progress, blur = mBinding.blurSeek.progress)
+ mUserViewModel.changeUserInfo(GsonUtils.toJson(entity), UserViewModel.TYPE_BACKGROUND)
+ }, {
+ it.printStackTrace()
+ mPostDialog?.dismiss()
+ })
+
+ }
+
+
+ private fun uploadImage(path: String): Single {
+ return Single.create {
+ UploadImageUtils.uploadImage(UploadImageUtils.UploadType.user_background, path, object : UploadImageUtils.OnUploadImageListener {
+ override fun onSuccess(imageUrl: String) {
+ it.onSuccess(imageUrl)
+ }
+
+ override fun onError(e: Throwable?) {
+ it.onError(e ?: Throwable())
+ }
+
+ override fun onProgress(total: Long, progress: Long) {
+
+ }
+
+ })
+ }
+ }
+
+
+ private fun selectPic(activity: Activity) {
+ PermissionHelper.checkStoragePermissionBeforeAction(activity, object : EmptyCallback {
+ override fun onCallback() {
+ Matisse.from(activity)
+ .choose(MimeType.ofImage())
+ .showSingleMediaType(true)
+ .countable(true)
+ .addFilter(GhMatisseFilter())
+ .maxSelectable(1)
+ .restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
+ .thumbnailScale(0.85f)
+ .imageEngine(PicassoEngine())
+ .forResult(MEDIA_STORE_REQUEST)
+ }
+ })
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ super.onActivityResult(requestCode, resultCode, data)
+
+ if (requestCode == MEDIA_STORE_REQUEST && resultCode == Activity.RESULT_OK) {
+ val selectedPaths = Matisse.obtainPathResult(data)
+ if (selectedPaths.size > 0) {
+ val intent = BackgroundClipActivity.getIntent(requireContext(), selectedPaths[0], mEntrance)
+ startActivityForResult(intent, REQUEST_CODE_IMAGE_CROP)
+ }
+ } else if (requestCode == REQUEST_CODE_IMAGE_CROP && resultCode == Activity.RESULT_OK) {
+ if (data != null) {
+ val imagePath = data.getStringExtra(CropImageActivity.RESULT_CLIP_PATH)
+ mOriginBitmap = BitmapUtils.getBitmapByFile(imagePath, Bitmap.Config.ARGB_8888)
+ val progress = mBinding.blurSeek.progress
+ mTempBitmap = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && progress != 0) {
+ BitmapUtils.getBlurBitmap(requireContext(), mOriginBitmap, progress)
+ } else {
+ Bitmap.createBitmap(mOriginBitmap)
+ }
+ mBinding.mineGhIv.setImageBitmap(mTempBitmap)
+ mBinding.personalHomeIv.setImageBitmap(mTempBitmap)
+ }
+ }
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ mOriginBitmap = null
+ mTempBitmap = null
+ }
+
+ companion object {
+ const val REQUEST_CODE_IMAGE_CROP = 100
+ const val MEDIA_STORE_REQUEST = 101
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/personalhome/background/PersonalityBackgroundActivity.kt b/app/src/main/java/com/gh/gamecenter/personalhome/background/PersonalityBackgroundActivity.kt
new file mode 100644
index 0000000000..556b57f661
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/personalhome/background/PersonalityBackgroundActivity.kt
@@ -0,0 +1,20 @@
+package com.gh.gamecenter.personalhome.background
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import com.gh.gamecenter.NormalActivity
+
+class PersonalityBackgroundActivity : NormalActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setNavigationTitle("个性背景")
+ }
+
+ companion object {
+ fun getIntent(context: Context): Intent {
+ return getTargetIntent(context, PersonalityBackgroundActivity::class.java, PersonalityBackgroundFragment::class.java)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/personalhome/background/PersonalityBackgroundAdapter.kt b/app/src/main/java/com/gh/gamecenter/personalhome/background/PersonalityBackgroundAdapter.kt
new file mode 100644
index 0000000000..2a38f4e0ec
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/personalhome/background/PersonalityBackgroundAdapter.kt
@@ -0,0 +1,45 @@
+package com.gh.gamecenter.personalhome.background
+
+import android.content.Context
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.gh.base.BaseRecyclerViewHolder
+import com.gh.common.util.ImageUtils
+import com.gh.common.util.visibleIf
+import com.gh.gamecenter.R
+import com.gh.gamecenter.databinding.AvatarBackgroundItemBinding
+import com.gh.gamecenter.entity.BackgroundImageEntity
+import com.gh.gamecenter.manager.UserManager
+import com.lightgame.adapter.BaseRecyclerAdapter
+import java.util.ArrayList
+
+class PersonalityBackgroundAdapter(context: Context,val mViewModel: PersonalityBackgroundViewModel) : BaseRecyclerAdapter(context) {
+
+ var mEntityList: ArrayList = arrayListOf()
+
+ fun setListData(datas: ArrayList) {
+ mEntityList.addAll(datas)
+ notifyDataSetChanged()
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
+ return PendantBackgroundViewHolder(AvatarBackgroundItemBinding.bind(mLayoutInflater.inflate(R.layout.avatar_background_item, parent, false)))
+ }
+
+ override fun getItemCount(): Int = mEntityList.size
+
+ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
+ if (holder is PendantBackgroundViewHolder) {
+ val entity = mEntityList[position]
+ ImageUtils.display(holder.binding.imageSdv, entity.url)
+ holder.binding.nameTv.text = entity.name
+ holder.binding.checkBorderView.visibleIf(UserManager.getInstance().userInfoEntity.background?.id == entity.id)
+ holder.binding.checkIv.visibleIf(UserManager.getInstance().userInfoEntity.background?.id == entity.id)
+ holder.itemView.setOnClickListener {
+ mViewModel.downLoadImage(mContext,entity)
+ }
+ }
+ }
+
+ class PendantBackgroundViewHolder(val binding: AvatarBackgroundItemBinding) : BaseRecyclerViewHolder(binding.root)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/personalhome/background/PersonalityBackgroundFragment.kt b/app/src/main/java/com/gh/gamecenter/personalhome/background/PersonalityBackgroundFragment.kt
new file mode 100644
index 0000000000..c16e5ba9d3
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/personalhome/background/PersonalityBackgroundFragment.kt
@@ -0,0 +1,114 @@
+package com.gh.gamecenter.personalhome.background
+
+import android.annotation.SuppressLint
+import android.app.Activity
+import android.content.Intent
+import android.content.pm.ActivityInfo
+import android.os.Bundle
+import android.view.View
+import android.widget.ImageView
+import android.widget.LinearLayout
+import androidx.lifecycle.Observer
+import androidx.recyclerview.widget.GridLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.gh.base.fragment.WaitingDialogFragment
+import com.gh.common.util.*
+import com.gh.common.view.GridSpacingItemColorDecoration
+import com.gh.common.view.GridSpacingItemDecoration
+import com.gh.gamecenter.CropImageActivity
+import com.gh.gamecenter.R
+import com.gh.gamecenter.normal.NormalFragment
+import com.gh.gamecenter.user.UserViewModel
+import com.halo.assistant.HaloApp
+import com.zhihu.matisse.Matisse
+import com.zhihu.matisse.MimeType
+import com.zhihu.matisse.engine.impl.PicassoEngine
+import kotterknife.bindView
+
+class PersonalityBackgroundFragment : NormalFragment() {
+ private val mUploadBackgroundLl by bindView(R.id.uploadBackgroundLl)
+ private val mRecommendRv by bindView(R.id.recommendRv)
+ private var mAdapter: PersonalityBackgroundAdapter? = null
+ private lateinit var mViewModel: PersonalityBackgroundViewModel
+ private lateinit var mUserViewModel: UserViewModel
+
+ private var mLoadingDialog: WaitingDialogFragment? = null
+
+ override fun getLayoutId(): Int = R.layout.personality_background_fragment
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ mUserViewModel = viewModelProvider(UserViewModel.Factory(HaloApp.getInstance().application))
+ mViewModel = viewModelProvider()
+ mUserViewModel.editObsUserinfo.observe(this, Observer {
+ mAdapter?.notifyDataSetChanged()
+ })
+ mViewModel.backgroundImagesLiveData.observe(this, Observer {
+ mAdapter?.setListData(it)
+ })
+ mViewModel.loadingLiveData.observe(this, Observer {
+ if (it) {
+ mLoadingDialog = WaitingDialogFragment.newInstance("下载图片中...")
+ mLoadingDialog?.show(childFragmentManager, null)
+ } else {
+ mLoadingDialog?.dismiss()
+ }
+ })
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ mRecommendRv.apply {
+ layoutManager = GridLayoutManager(requireContext(), 3)
+ mAdapter = PersonalityBackgroundAdapter(requireContext(), mViewModel)
+ addItemDecoration(GridSpacingItemColorDecoration(requireContext(), 8, 20, R.color.white))
+ adapter = mAdapter
+ }
+ mUploadBackgroundLl.setOnClickListener {
+ selectPic(requireActivity())
+ }
+
+ }
+
+ private fun selectPic(activity: Activity) {
+ PermissionHelper.checkStoragePermissionBeforeAction(activity, object : EmptyCallback {
+ override fun onCallback() {
+ Matisse.from(activity)
+ .choose(MimeType.ofImage())
+ .showSingleMediaType(true)
+ .countable(true)
+ .addFilter(GhMatisseFilter())
+ .maxSelectable(1)
+ .restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
+ .thumbnailScale(0.85f)
+ .imageEngine(PicassoEngine())
+ .forResult(MEDIA_STORE_REQUEST)
+ }
+ })
+ }
+
+ @SuppressLint("Recycle")
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ super.onActivityResult(requestCode, resultCode, data)
+
+ if (requestCode == MEDIA_STORE_REQUEST && resultCode == Activity.RESULT_OK) {
+ val selectedPaths = Matisse.obtainPathResult(data)
+ if (selectedPaths.size > 0) {
+ val intent = BackgroundClipActivity.getIntent(requireContext(), selectedPaths[0], mEntrance)
+ startActivityForResult(intent, REQUEST_CODE_IMAGE_CROP)
+ }
+ } else if (requestCode == REQUEST_CODE_IMAGE_CROP && resultCode == Activity.RESULT_OK) {
+ if (data != null) {
+ val imagePath = data.getStringExtra(CropImageActivity.RESULT_CLIP_PATH)
+ val intent = BackgroundPreviewActivity.getIntent(requireContext(), imagePath, null)
+ requireContext().startActivity(intent)
+ }
+ }
+ }
+
+ companion object {
+ const val REQUEST_CODE_IMAGE_CROP = 100
+ const val MEDIA_STORE_REQUEST = 101
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/personalhome/background/PersonalityBackgroundViewModel.kt b/app/src/main/java/com/gh/gamecenter/personalhome/background/PersonalityBackgroundViewModel.kt
new file mode 100644
index 0000000000..4a41141f44
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/personalhome/background/PersonalityBackgroundViewModel.kt
@@ -0,0 +1,68 @@
+package com.gh.gamecenter.personalhome.background
+
+import android.annotation.SuppressLint
+import android.app.Application
+import android.content.Context
+import android.net.Uri
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.MutableLiveData
+import com.bytedance.sdk.open.aweme.utils.Md5Utils
+import com.gh.common.util.BitmapUtils
+import com.gh.gamecenter.entity.BackgroundImageEntity
+import com.gh.gamecenter.retrofit.Response
+import com.gh.gamecenter.retrofit.RetrofitManager
+import com.squareup.picasso.Picasso
+import io.reactivex.Single
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.schedulers.Schedulers
+import java.io.File
+
+class PersonalityBackgroundViewModel(application: Application) : AndroidViewModel(application) {
+
+ val loadingLiveData= MutableLiveData()
+ val backgroundImagesLiveData = MutableLiveData>()
+
+ init {
+ getBackgroundImages()
+ }
+
+ fun getBackgroundImages() {
+ RetrofitManager.getInstance(getApplication()).api
+ .backgroundImages
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(object : Response>() {
+ override fun onResponse(response: ArrayList?) {
+ super.onResponse(response)
+ if (!response.isNullOrEmpty()) {
+ backgroundImagesLiveData.postValue(response)
+ }
+ }
+ })
+ }
+
+ @SuppressLint("CheckResult")
+ fun downLoadImage(context: Context, entity: BackgroundImageEntity) {
+ loadingLiveData.postValue(true)
+ Single.just(entity.url)
+ .map {
+ Picasso.with(getApplication()).load(Uri.parse(it)).priority(Picasso.Priority.HIGH).get()
+ }
+ .map {
+ val fileName = entity.url.substring(entity.url.lastIndexOf("/") + 1)
+ val filePath: String = "${context.cacheDir.absolutePath}${File.separator}$fileName"
+ BitmapUtils.saveBitmap(it, filePath)
+ filePath
+ }
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe({
+ loadingLiveData.postValue(false)
+ val intent = BackgroundPreviewActivity.getIntent(context, it, entity)
+ context.startActivity(intent)
+ }, {
+ it.printStackTrace()
+ loadingLiveData.postValue(false)
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/personalhome/border/AvatarBorderActivity.kt b/app/src/main/java/com/gh/gamecenter/personalhome/border/AvatarBorderActivity.kt
new file mode 100644
index 0000000000..9da71e87d0
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/personalhome/border/AvatarBorderActivity.kt
@@ -0,0 +1,33 @@
+package com.gh.gamecenter.personalhome.border
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import com.gh.base.BaseActivity
+import com.gh.common.util.DisplayUtils
+import com.gh.gamecenter.R
+
+class AvatarBorderActivity : BaseActivity() {
+
+ override fun getLayoutId(): Int {
+ return R.layout.activity_amway
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ DisplayUtils.transparentStatusBar(this)
+
+ val containerFragment = supportFragmentManager.findFragmentByTag(AvatarBorderFragment::class.java.simpleName)
+ ?: AvatarBorderFragment().with(intent.extras)
+ // 若 placeholder 外层为 RelativeLayout 的话,会出现莫名的偏移
+ supportFragmentManager.beginTransaction().replace(R.id.placeholder, containerFragment, AvatarBorderFragment::class.java.simpleName).commitAllowingStateLoss()
+ }
+
+ companion object {
+ fun getIntent(context: Context): Intent {
+ return Intent(context, AvatarBorderActivity::class.java)
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/personalhome/border/AvatarBorderFragment.kt b/app/src/main/java/com/gh/gamecenter/personalhome/border/AvatarBorderFragment.kt
new file mode 100644
index 0000000000..c90ab49dff
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/personalhome/border/AvatarBorderFragment.kt
@@ -0,0 +1,127 @@
+package com.gh.gamecenter.personalhome.border
+
+import android.os.Bundle
+import android.view.View
+import android.view.ViewGroup
+import androidx.core.content.ContextCompat
+import androidx.core.view.ViewCompat
+import androidx.databinding.DataBindingUtil
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.Observer
+import com.gh.base.fragment.BaseFragment_TabLayout
+import com.gh.base.fragment.WaitingDialogFragment
+import com.gh.common.util.*
+import com.gh.gamecenter.ImageViewerActivity
+import com.gh.gamecenter.R
+import com.gh.gamecenter.SelectUserIconActivity
+import com.gh.gamecenter.databinding.FragmentAvatarBorderBinding
+import com.gh.gamecenter.entity.AvatarBorderEntity
+import com.gh.gamecenter.manager.UserManager
+import com.gh.gamecenter.user.UserViewModel
+import com.halo.assistant.HaloApp
+
+class AvatarBorderFragment : BaseFragment_TabLayout() {
+
+ private lateinit var mUserViewModel: UserViewModel
+
+ lateinit var mBinding: FragmentAvatarBorderBinding
+
+ private var mPostDialog: WaitingDialogFragment? = null
+
+ var selectAvatarBorderEntity: AvatarBorderEntity? = null
+
+
+ override fun getInflatedLayout(): View {
+ mBinding = DataBindingUtil.inflate(layoutInflater, R.layout.fragment_avatar_border, null, false)
+ return mBinding.root
+ }
+
+ override fun initFragmentList(fragments: MutableList) {
+ fragments.add(ChooseAvatarBorderFragment())
+ }
+
+ override fun initTabTitleList(tabTitleList: MutableList) {
+ tabTitleList.add("推荐边框")
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ mUserViewModel = viewModelProvider(UserViewModel.Factory(HaloApp.getInstance().application))
+ mUserViewModel.loginObsUserinfo.observe(this, Observer {
+ ImageUtils.display(mBinding.forumBackground, it.data.background?.url)
+ mBinding.userAvatar.display(it.data.iconBorder?.url, it.data.icon ?: "")
+ })
+ mUserViewModel.editObsUserinfo.observe(this, Observer {
+ mBinding.userAvatar.displayAvatar(it.data.icon ?: "")
+ })
+ mUserViewModel.uploadAvatarBorder.observe(this, Observer {
+ mPostDialog?.dismiss()
+ if (it) {
+ requireActivity().finish()
+ mUserViewModel.uploadAvatarBorder.value = false
+ }
+ })
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ ViewCompat.setOnApplyWindowInsetsListener(mBinding.appbar) { _, insets ->
+ (mBinding.toolbar.layoutParams as ViewGroup.MarginLayoutParams).topMargin = insets.systemWindowInsetTop
+ insets.consumeSystemWindowInsets()
+ }
+
+ mBinding.toolbar.setNavigationOnClickListener { requireActivity().finish() }
+
+ mBinding.collapsingToolbar.scrimShownAction = {
+ DisplayUtils.setLightStatusBar(requireActivity(), it)
+ if (it) {
+ mBinding.titleTv.alpha = 1F
+ mBinding.titleTv.setTextColor(ContextCompat.getColor(requireContext(), R.color.black))
+ mBinding.toolbar.navigationIcon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_bar_back)
+ } else {
+ mBinding.titleTv.setTextColor(ContextCompat.getColor(requireContext(), R.color.white))
+ mBinding.toolbar.navigationIcon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_toolbar_back_white)
+ }
+ }
+
+ mBinding.userAvatar.setOnClickListener {
+ startActivity(ImageViewerActivity.getIntent(requireContext(), arrayListOf(UserManager.getInstance().userInfoEntity.icon
+ ?: ""), 0, mBinding.userAvatar, "$mEntrance+(头像挂件)"))
+ }
+
+ mBinding.changeAvatarTv.setOnClickListener {
+ startActivity(SelectUserIconActivity.getIntent(context))
+ }
+
+ mBinding.commitTv.setOnClickListener {
+ if (selectAvatarBorderEntity != null) {
+ mPostDialog = WaitingDialogFragment.newInstance("加载中...")
+ mPostDialog?.show(childFragmentManager, null)
+
+ if (mBinding.commitTv.text == "停用挂件") {
+ mUserViewModel.changeUserInfo(GsonUtils.toJson(AvatarBorderEntity("", "", "")), UserViewModel.TYPE_ICON_BORDER)
+ } else {
+ mUserViewModel.changeUserInfo(GsonUtils.toJson(selectAvatarBorderEntity), UserViewModel.TYPE_ICON_BORDER)
+ }
+ }
+ }
+ }
+
+ fun choosePendant(entity: AvatarBorderEntity, isSelected: Boolean) {
+ if (isSelected) {
+ selectAvatarBorderEntity = entity
+ mBinding.userAvatar.displayBorder(entity.url)
+ mBinding.commitTv.isEnabled = true
+ if (entity.id == UserManager.getInstance().userInfoEntity.iconBorder?.id) {
+ mBinding.commitTv.text = "停用挂件"
+ } else {
+ mBinding.commitTv.text = "使用"
+ }
+ } else {
+ selectAvatarBorderEntity = null
+ mBinding.userAvatar.displayBorder("")
+ mBinding.commitTv.text = "使用"
+ mBinding.commitTv.isEnabled = false
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/personalhome/border/ChooseAvatarBorderAdapter.kt b/app/src/main/java/com/gh/gamecenter/personalhome/border/ChooseAvatarBorderAdapter.kt
new file mode 100644
index 0000000000..7ff23fd55e
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/personalhome/border/ChooseAvatarBorderAdapter.kt
@@ -0,0 +1,66 @@
+package com.gh.gamecenter.personalhome.border
+
+import android.content.Context
+import android.view.View
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.gh.base.BaseRecyclerViewHolder
+import com.gh.common.util.ImageUtils
+import com.gh.common.util.goneIf
+import com.gh.gamecenter.R
+import com.gh.gamecenter.databinding.AvatarItemBinding
+import com.gh.gamecenter.entity.AvatarBorderEntity
+import com.gh.gamecenter.manager.UserManager
+import com.lightgame.adapter.BaseRecyclerAdapter
+import java.util.*
+
+class ChooseAvatarBorderAdapter(context: Context, val clickCallback: (entity: AvatarBorderEntity, isSelected: Boolean) -> Unit) : BaseRecyclerAdapter(context) {
+
+ var entityList: ArrayList = arrayListOf()
+ var selectedEntity: AvatarBorderEntity? = null
+
+ fun setListData(updateData: List) {
+ entityList.clear()
+ entityList.addAll(updateData)
+ notifyDataSetChanged()
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
+ return PendantBackgroundViewHolder(AvatarItemBinding.bind(mLayoutInflater.inflate(R.layout.avatar_item, parent, false)))
+ }
+
+ override fun getItemCount(): Int = entityList.size
+
+ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
+ if (holder is PendantBackgroundViewHolder) {
+ val borderEntity = entityList[position]
+ ImageUtils.display(holder.binding.imageSdv, borderEntity.url)
+ holder.binding.nameTv.text = borderEntity.name
+ val iconBorder = UserManager.getInstance().userInfoEntity.iconBorder
+ if (iconBorder?.id != borderEntity.id) {
+ holder.binding.checkIv.visibility = View.GONE
+ } else {
+ holder.binding.checkIv.visibility = View.VISIBLE
+ clickCallback.invoke(borderEntity, true)
+ }
+ holder.itemView.setOnClickListener {
+ if (selectedEntity == null) {
+ selectedEntity = borderEntity
+ clickCallback.invoke(borderEntity, true)
+ } else {
+ selectedEntity = if (selectedEntity?.id == borderEntity.id) {
+ clickCallback.invoke(borderEntity, false)
+ null
+ } else {
+ clickCallback.invoke(borderEntity, true)
+ borderEntity
+ }
+ }
+ holder.binding.checkIv.goneIf(selectedEntity?.id != borderEntity.id)
+ holder.binding.checkBorderView.goneIf(selectedEntity?.id != borderEntity.id)
+ }
+ }
+ }
+
+ class PendantBackgroundViewHolder(val binding: AvatarItemBinding) : BaseRecyclerViewHolder(binding.root)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/personalhome/border/ChooseAvatarBorderFragment.kt b/app/src/main/java/com/gh/gamecenter/personalhome/border/ChooseAvatarBorderFragment.kt
new file mode 100644
index 0000000000..08e157fe0a
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/personalhome/border/ChooseAvatarBorderFragment.kt
@@ -0,0 +1,76 @@
+package com.gh.gamecenter.personalhome.border
+
+import android.os.Bundle
+import android.view.View
+import android.view.ViewGroup
+import android.widget.LinearLayout
+import android.widget.RelativeLayout
+import androidx.lifecycle.Observer
+import androidx.recyclerview.widget.GridLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
+import com.gh.common.util.dip2px
+import com.gh.common.util.viewModelProvider
+import com.gh.common.view.GridSpacingItemColorDecoration
+import com.gh.gamecenter.R
+import com.gh.gamecenter.normal.NormalFragment
+import kotterknife.bindView
+
+class ChooseAvatarBorderFragment : NormalFragment() {
+
+ val mRefresh by bindView(R.id.list_refresh)
+ val mListRv by bindView(R.id.list_rv)
+ val mReuseLoading by bindView(R.id.reuse_ll_loading)
+ val mNoConnection by bindView(R.id.reuse_no_connection)
+ val mNoneData by bindView(R.id.reuse_none_data)
+
+ private var mAdapter: ChooseAvatarBorderAdapter? = null
+ private var mViewModel: ChooseAvatarBorderViewModel? = null
+
+ override fun getLayoutId(): Int = R.layout.fragment_list_base
+
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ mViewModel = viewModelProvider()
+ mViewModel?.pendantsLiveData?.observe(this, Observer {
+ mReuseLoading.visibility = View.GONE
+ if (it != null) {
+ mNoConnection.visibility = View.GONE
+ if (it.isNotEmpty()) {
+ mNoneData.visibility = View.GONE
+ mAdapter?.setListData(it)
+ } else {
+ mNoneData.visibility = View.VISIBLE
+ }
+ } else {
+ mNoneData.visibility = View.GONE
+ mNoConnection.visibility = View.VISIBLE
+ }
+ })
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ mRefresh.isEnabled = false
+ val params = mRefresh.layoutParams as RelativeLayout.LayoutParams
+ params.leftMargin=16f.dip2px()
+ params.rightMargin=16f.dip2px()
+ params.topMargin=10f.dip2px()
+ mRefresh.layoutParams=params
+ mListRv.apply {
+ layoutManager = GridLayoutManager(requireContext(), 3)
+ mAdapter = ChooseAvatarBorderAdapter(requireContext()) { entity, isSelected ->
+ val avatarPendantFragment = parentFragment as? AvatarBorderFragment
+ avatarPendantFragment?.choosePendant(entity,isSelected)
+ }
+ addItemDecoration(GridSpacingItemColorDecoration(requireContext(), 8, 8, R.color.white))
+ adapter = mAdapter
+ }
+
+ mNoConnection.setOnClickListener {
+ mViewModel?.getPendants()
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/personalhome/border/ChooseAvatarBorderViewModel.kt b/app/src/main/java/com/gh/gamecenter/personalhome/border/ChooseAvatarBorderViewModel.kt
new file mode 100644
index 0000000000..ad32837491
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/personalhome/border/ChooseAvatarBorderViewModel.kt
@@ -0,0 +1,37 @@
+package com.gh.gamecenter.personalhome.border
+
+import android.app.Application
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.MutableLiveData
+import com.gh.gamecenter.entity.AvatarBorderEntity
+import com.gh.gamecenter.retrofit.Response
+import com.gh.gamecenter.retrofit.RetrofitManager
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.schedulers.Schedulers
+import retrofit2.HttpException
+
+class ChooseAvatarBorderViewModel(application: Application) : AndroidViewModel(application) {
+ val pendantsLiveData = MutableLiveData>()
+
+ init {
+ getPendants()
+ }
+
+ fun getPendants() {
+ RetrofitManager.getInstance(getApplication()).api
+ .pendants
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(object : Response>() {
+ override fun onResponse(response: ArrayList?) {
+ super.onResponse(response)
+ pendantsLiveData.postValue(response)
+ }
+
+ override fun onFailure(e: HttpException?) {
+ super.onFailure(e)
+ pendantsLiveData.postValue(null)
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java b/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java
index 05212eabaa..e6b2650467 100644
--- a/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java
+++ b/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java
@@ -8,6 +8,8 @@ import com.gh.gamecenter.entity.AmwayCommentEntity;
import com.gh.gamecenter.entity.ApkEntity;
import com.gh.gamecenter.entity.AppEntity;
import com.gh.gamecenter.entity.AuthDialogEntity;
+import com.gh.gamecenter.entity.AvatarBorderEntity;
+import com.gh.gamecenter.entity.BackgroundImageEntity;
import com.gh.gamecenter.entity.BadgeEntity;
import com.gh.gamecenter.entity.CategoryEntity;
import com.gh.gamecenter.entity.CommentEntity;
@@ -2629,5 +2631,18 @@ public interface ApiService {
* 取消点赞游戏视频的评论
*/
@POST("videos/{video_id}/comments/{comment_id}:unvote")
- Observable unVoteVideoComment(@Path("video_id") String videoId,@Path("comment_id") String commentId);
+ Observable unVoteVideoComment(@Path("video_id") String videoId, @Path("comment_id") String commentId);
+
+ /**
+ * 获取个人主页的默认背景图列表
+ */
+ @GET("users/background_images")
+ Observable> getBackgroundImages();
+
+ /**
+ * 获取用户头像默认边框列表
+ */
+ @GET("users/icon_borders")
+ Observable> getPendants();
+
}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/user/UserRepository.java b/app/src/main/java/com/gh/gamecenter/user/UserRepository.java
index 7b6f42ef7e..54648bd6e4 100644
--- a/app/src/main/java/com/gh/gamecenter/user/UserRepository.java
+++ b/app/src/main/java/com/gh/gamecenter/user/UserRepository.java
@@ -6,9 +6,6 @@ import android.os.Build;
import android.preference.PreferenceManager;
import android.text.TextUtils;
-import androidx.lifecycle.LiveData;
-import androidx.lifecycle.MediatorLiveData;
-
import com.gh.common.PushManager;
import com.gh.common.constant.Constants;
import com.gh.common.im.ImManager;
@@ -22,8 +19,10 @@ import com.gh.common.util.LoginUtils;
import com.gh.common.util.SPUtils;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.R;
+import com.gh.gamecenter.entity.BackgroundImageEntity;
import com.gh.gamecenter.entity.IdCardEntity;
import com.gh.gamecenter.entity.LoginTokenEntity;
+import com.gh.gamecenter.entity.AvatarBorderEntity;
import com.gh.gamecenter.entity.TokenEntity;
import com.gh.gamecenter.entity.UserInfoEntity;
import com.gh.gamecenter.eventbus.EBReuse;
@@ -44,6 +43,8 @@ import org.json.JSONObject;
import java.util.HashMap;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MediatorLiveData;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
@@ -66,6 +67,8 @@ public class UserRepository {
private final MediatorLiveData> mLoginObsResponseUserInfo = new MediatorLiveData<>();
private final MediatorLiveData> mEditObsResponseUserInfo = new MediatorLiveData<>();
+ private final MediatorLiveData mUploadBackgroundLiveData = new MediatorLiveData<>();
+ private final MediatorLiveData mUploadAvatarBorderLiveData = new MediatorLiveData<>();
private final MediatorLiveData mObservableLoginToken = new MediatorLiveData<>();
@@ -286,7 +289,9 @@ public class UserRepository {
}
JSONObject object = new JSONObject();
try {
- if (editType.equals(UserViewModel.TYPE_ID_CARD)) {
+ if (editType.equals(UserViewModel.TYPE_ID_CARD) ||
+ editType.equals(UserViewModel.TYPE_BACKGROUND) ||
+ editType.equals(UserViewModel.TYPE_ICON_BORDER)) {
object = new JSONObject();
object.put(editType, new JSONObject(content));
} else {
@@ -332,6 +337,15 @@ public class UserRepository {
break;
case UserViewModel.TYPE_INTRODUCE:
mCacheUserInfoEntity.setIntroduce(content);
+ break;
+ case UserViewModel.TYPE_BACKGROUND:
+ mCacheUserInfoEntity.setBackground(GsonUtils.fromJson(content, BackgroundImageEntity.class));
+ mUploadBackgroundLiveData.postValue(true);
+ break;
+ case UserViewModel.TYPE_ICON_BORDER:
+ mCacheUserInfoEntity.setIconBorder(GsonUtils.fromJson(content, AvatarBorderEntity.class));
+ mUploadAvatarBorderLiveData.postValue(true);
+ break;
}
userInfoHandle(mCacheUserInfoEntity, true);
@@ -346,6 +360,12 @@ public class UserRepository {
value.setThrowable(e.getThrowable());
value.setHttpException(httpException);
mEditObsResponseUserInfo.postValue(value);
+ if (editType.equals(UserViewModel.TYPE_BACKGROUND)) {
+ mUploadBackgroundLiveData.postValue(false);
+ }
+ if (editType.equals(UserViewModel.TYPE_ICON_BORDER)) {
+ mUploadAvatarBorderLiveData.postValue(false);
+ }
if (httpException == null || httpException.code() == Constants.NOT_NETWORK_CODE) {
Utils.toast(mContext, "请检查网络是否可用");
@@ -488,4 +508,11 @@ public class UserRepository {
public MediatorLiveData> getEditObsUserInfo() {
return mEditObsResponseUserInfo;
}
+
+ public MediatorLiveData getUploadBackgroundLiveData() {
+ return mUploadBackgroundLiveData;
+ }
+ public MediatorLiveData getUploadAvatarBorderLiveData() {
+ return mUploadAvatarBorderLiveData;
+ }
}
diff --git a/app/src/main/java/com/gh/gamecenter/user/UserViewModel.java b/app/src/main/java/com/gh/gamecenter/user/UserViewModel.java
index 902f578584..67c5d1335c 100644
--- a/app/src/main/java/com/gh/gamecenter/user/UserViewModel.java
+++ b/app/src/main/java/com/gh/gamecenter/user/UserViewModel.java
@@ -2,16 +2,17 @@ package com.gh.gamecenter.user;
import android.app.Application;
-import androidx.annotation.NonNull;
-import androidx.lifecycle.AndroidViewModel;
-import androidx.lifecycle.LiveData;
-import androidx.lifecycle.ViewModel;
-import androidx.lifecycle.ViewModelProvider;
-
import com.gh.gamecenter.entity.UserInfoEntity;
import org.json.JSONObject;
+import androidx.annotation.NonNull;
+import androidx.lifecycle.AndroidViewModel;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MediatorLiveData;
+import androidx.lifecycle.ViewModel;
+import androidx.lifecycle.ViewModelProvider;
+
/**
* Created by khy on 28/11/17.
*/
@@ -32,17 +33,23 @@ public class UserViewModel extends AndroidViewModel {
public static final String TYPE_REGION = "region";
public static final String TYPE_ID_CARD = "id_card";
public static final String TYPE_INTRODUCE = "introduce";
+ public static final String TYPE_BACKGROUND = "background";
+ public static final String TYPE_ICON_BORDER = "icon_border";
private UserRepository mUserRepository;
private final LiveData> mLoginLiveUserInfo;
private final LiveData> mEditLiveUserInfo;
+ private final MediatorLiveData mUploadBackground;
+ private final MediatorLiveData mUploadAvatarBorder;
public UserViewModel(@NonNull Application application, UserRepository repository) {
super(application);
mUserRepository = repository;
mLoginLiveUserInfo = repository.getLoginUserInfo();
mEditLiveUserInfo = repository.getEditObsUserInfo();
+ mUploadBackground = repository.getUploadBackgroundLiveData();
+ mUploadAvatarBorder = repository.getUploadAvatarBorderLiveData();
}
public void retryCheckLogin() {
@@ -57,6 +64,14 @@ public class UserViewModel extends AndroidViewModel {
return mEditLiveUserInfo;
}
+ public MediatorLiveData getUploadBackground() {
+ return mUploadBackground;
+ }
+
+ public MediatorLiveData getUploadAvatarBorder() {
+ return mUploadAvatarBorder;
+ }
+
public void login(JSONObject content, LoginTag loginTag) {
mUserRepository.login(content, loginTag);
}
diff --git a/app/src/main/res/drawable-xxhdpi/ic_avatar_border_select.png b/app/src/main/res/drawable-xxhdpi/ic_avatar_border_select.png
new file mode 100644
index 0000000000..4c9cca48d4
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_avatar_border_select.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_background_add.png b/app/src/main/res/drawable-xxhdpi/ic_background_add.png
new file mode 100644
index 0000000000..3994b92f0e
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_background_add.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_seekbar_thumb.png b/app/src/main/res/drawable-xxhdpi/ic_seekbar_thumb.png
new file mode 100644
index 0000000000..b6d6bbe35b
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_seekbar_thumb.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/bg_avatar_border.webp b/app/src/main/res/drawable-xxxhdpi/bg_avatar_border.webp
new file mode 100644
index 0000000000..babc645b86
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/bg_avatar_border.webp differ
diff --git a/app/src/main/res/drawable-xxxhdpi/preview_home.png b/app/src/main/res/drawable-xxxhdpi/preview_home.png
new file mode 100644
index 0000000000..81b5c8e1b0
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/preview_home.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/preview_home_full.png b/app/src/main/res/drawable-xxxhdpi/preview_home_full.png
new file mode 100644
index 0000000000..a624378a5e
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/preview_home_full.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/preview_mine.png b/app/src/main/res/drawable-xxxhdpi/preview_mine.png
new file mode 100644
index 0000000000..243c58f4b3
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/preview_mine.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/preview_mine_full.png b/app/src/main/res/drawable-xxxhdpi/preview_mine_full.png
new file mode 100644
index 0000000000..f00a07dae3
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/preview_mine_full.png differ
diff --git a/app/src/main/res/drawable/background_shape_white_radius_4.xml b/app/src/main/res/drawable/background_shape_white_radius_4.xml
new file mode 100644
index 0000000000..02abad050c
--- /dev/null
+++ b/app/src/main/res/drawable/background_shape_white_radius_4.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_background_preview_top.xml b/app/src/main/res/drawable/bg_background_preview_top.xml
new file mode 100644
index 0000000000..1f9d557a6d
--- /dev/null
+++ b/app/src/main/res/drawable/bg_background_preview_top.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_border_blue_radius_4_width_1.xml b/app/src/main/res/drawable/bg_border_blue_radius_4_width_1.xml
new file mode 100644
index 0000000000..54e5c4e614
--- /dev/null
+++ b/app/src/main/res/drawable/bg_border_blue_radius_4_width_1.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_shape_fa_radius_4.xml b/app/src/main/res/drawable/bg_shape_fa_radius_4.xml
new file mode 100644
index 0000000000..0a9ed71f8f
--- /dev/null
+++ b/app/src/main/res/drawable/bg_shape_fa_radius_4.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/border_round_ccc_999.xml b/app/src/main/res/drawable/border_round_ccc_999.xml
new file mode 100644
index 0000000000..4eca779200
--- /dev/null
+++ b/app/src/main/res/drawable/border_round_ccc_999.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/seekbar_progress.xml b/app/src/main/res/drawable/seekbar_progress.xml
new file mode 100644
index 0000000000..79623cf620
--- /dev/null
+++ b/app/src/main/res/drawable/seekbar_progress.xml
@@ -0,0 +1,23 @@
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_background_clip.xml b/app/src/main/res/layout/activity_background_clip.xml
new file mode 100644
index 0000000000..53838c319b
--- /dev/null
+++ b/app/src/main/res/layout/activity_background_clip.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/avatar_background_item.xml b/app/src/main/res/layout/avatar_background_item.xml
new file mode 100644
index 0000000000..633af49120
--- /dev/null
+++ b/app/src/main/res/layout/avatar_background_item.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/avatar_item.xml b/app/src/main/res/layout/avatar_item.xml
new file mode 100644
index 0000000000..3c792afa86
--- /dev/null
+++ b/app/src/main/res/layout/avatar_item.xml
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_avatar_border.xml b/app/src/main/res/layout/fragment_avatar_border.xml
new file mode 100644
index 0000000000..4757631faa
--- /dev/null
+++ b/app/src/main/res/layout/fragment_avatar_border.xml
@@ -0,0 +1,184 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_background_preview.xml b/app/src/main/res/layout/fragment_background_preview.xml
new file mode 100644
index 0000000000..310c0798ba
--- /dev/null
+++ b/app/src/main/res/layout/fragment_background_preview.xml
@@ -0,0 +1,222 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/personality_background_fragment.xml b/app/src/main/res/layout/personality_background_fragment.xml
new file mode 100644
index 0000000000..8395f14745
--- /dev/null
+++ b/app/src/main/res/layout/personality_background_fragment.xml
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml
index 7d09d1e1e2..ef792e93fe 100644
--- a/app/src/main/res/values/attrs.xml
+++ b/app/src/main/res/values/attrs.xml
@@ -1,36 +1,36 @@
-
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
@@ -74,54 +74,68 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
-
-
-
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
+
+
+
-
+
-
+
-
+
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 2b91ee7d3f..b528ab6fe7 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -82,6 +82,7 @@
@android:color/black
#1A000000
#4D000000
+ #66000000
#80000000
#99FFFFFF
@@ -195,5 +196,6 @@
#140B6D
#16161A
#28282E
+ #3796FF
\ No newline at end of file