diff --git a/app/src/main/java/com/gh/common/util/OssUploadUtils.kt b/app/src/main/java/com/gh/common/util/OssUploadUtils.kt new file mode 100644 index 0000000000..28f2d357e4 --- /dev/null +++ b/app/src/main/java/com/gh/common/util/OssUploadUtils.kt @@ -0,0 +1,88 @@ +package com.gh.common.util + +import com.alibaba.sdk.android.oss.ClientConfiguration +import com.alibaba.sdk.android.oss.ClientException +import com.alibaba.sdk.android.oss.OSSClient +import com.alibaba.sdk.android.oss.ServiceException +import com.alibaba.sdk.android.oss.callback.OSSCompletedCallback +import com.alibaba.sdk.android.oss.common.auth.OSSStsTokenCredentialProvider +import com.alibaba.sdk.android.oss.internal.OSSAsyncTask +import com.alibaba.sdk.android.oss.model.PutObjectRequest +import com.alibaba.sdk.android.oss.model.PutObjectResult +import com.gh.gamecenter.entity.OssEntity +import com.gh.gamecenter.retrofit.RetrofitManager +import com.halo.assistant.HaloApp +import io.reactivex.Single +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers + + +object OssUploadUtils { + //上传文件类型 + enum class UploadType(val value: String) { + GAME("game")//后缀apk + } + + //获取Oss配置 + private fun getOssUpdateConfig(type: UploadType): Single { + return RetrofitManager.getInstance(HaloApp.getInstance().application) + .api + .getOssUpdateConfig(type.value) + .subscribeOn(Schedulers.io()) + + } + + //异步上传文件 + @JvmStatic + fun uploadFile(path: String, uploadType: UploadType, listener: OnUploadFileListener?): Disposable { + return getOssUpdateConfig(uploadType) + .subscribeOn(Schedulers.io()) + .flatMap { mOssEntity -> + Single.create { + val conf = ClientConfiguration() + conf.connectionTimeout = 15 * 1000 + conf.socketTimeout = 15 * 1000 + conf.maxConcurrentRequest = 5 + conf.maxErrorRetry = 2 + + val credentialProvider = OSSStsTokenCredentialProvider(mOssEntity.accessKeyId, mOssEntity.accessKeySecret, mOssEntity.securityToken) + val oss = OSSClient(HaloApp.getInstance().application, mOssEntity.endPoint, credentialProvider, conf) + + // 构造上传请求 + val put = PutObjectRequest(mOssEntity.bucket, mOssEntity.key, path) + + val task: OSSAsyncTask<*> = oss.asyncPutObject(put, object : OSSCompletedCallback { + override fun onSuccess(request: PutObjectRequest?, result: PutObjectResult) { + it.onSuccess(mOssEntity.domain + mOssEntity.key) + } + + override fun onFailure(request: PutObjectRequest?, clientExcepion: ClientException?, serviceException: ServiceException?) { + clientExcepion?.printStackTrace() + serviceException?.printStackTrace() + if (serviceException != null) { + it.onError(Throwable(message = clientExcepion?.message + "/" + serviceException.message)) + } + } + }) + } + }.subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { url, throwable -> + if (url.isNotEmpty()) { + listener?.onSuccess(url) + return@subscribe + } + if (throwable != null) { + listener?.onError(throwable) + } + + } + + } + + interface OnUploadFileListener { + fun onSuccess(url: String) + fun onError(e: Throwable?) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/util/UriUtils.java b/app/src/main/java/com/gh/common/util/UriUtils.java new file mode 100644 index 0000000000..b8966d1c2e --- /dev/null +++ b/app/src/main/java/com/gh/common/util/UriUtils.java @@ -0,0 +1,127 @@ +package com.gh.common.util; + +import android.annotation.SuppressLint; +import android.content.ContentUris; +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.os.Build; +import android.os.Environment; +import android.provider.DocumentsContract; +import android.provider.MediaStore; + +public class UriUtils { + + @SuppressLint("NewApi") + public static String getPath(final Context context, final Uri uri) { + + final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; + + // DocumentProvider + if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) { + // ExternalStorageProvider + if (isExternalStorageDocument(uri)) { + final String docId = DocumentsContract.getDocumentId(uri); + final String[] split = docId.split(":"); + final String type = split[0]; + + if ("primary".equalsIgnoreCase(type)) { + return Environment.getExternalStorageDirectory() + "/" + split[1]; + } + } + // DownloadsProvider + else if (isDownloadsDocument(uri)) { + + final String id = DocumentsContract.getDocumentId(uri); + final Uri contentUri = ContentUris.withAppendedId( + Uri.parse("content://downloads/public_downloads"), Long.parseLong(id)); + + return getDataColumn(context, contentUri, null, null); + } + // MediaProvider + else if (isMediaDocument(uri)) { + final String docId = DocumentsContract.getDocumentId(uri); + final String[] split = docId.split(":"); + final String type = split[0]; + + Uri contentUri = null; + if ("image".equals(type)) { + contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; + } else if ("video".equals(type)) { + contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; + } else if ("audio".equals(type)) { + contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; + } + + final String selection = "_id=?"; + final String[] selectionArgs = new String[]{split[1]}; + + return getDataColumn(context, contentUri, selection, selectionArgs); + } + } + // MediaStore (and general) + else if ("content".equalsIgnoreCase(uri.getScheme())) { + return getDataColumn(context, uri, null, null); + } + // File + else if ("file".equalsIgnoreCase(uri.getScheme())) { + return uri.getPath(); + } + return null; + } + + /** + * Get the value of the data column for this Uri. This is useful for + * MediaStore Uris, and other file-based ContentProviders. + * + * @param context The context. + * @param uri The Uri to query. + * @param selection (Optional) Filter used in the query. + * @param selectionArgs (Optional) Selection arguments used in the query. + * @return The value of the _data column, which is typically a file path. + */ + private static String getDataColumn(Context context, Uri uri, String selection, + String[] selectionArgs) { + + Cursor cursor = null; + final String column = "_data"; + final String[] projection = {column}; + + try { + cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, + null); + if (cursor != null && cursor.moveToFirst()) { + final int column_index = cursor.getColumnIndexOrThrow(column); + return cursor.getString(column_index); + } + } finally { + if (cursor != null) + cursor.close(); + } + return null; + } + + /** + * @param uri The Uri to check. + * @return Whether the Uri authority is ExternalStorageProvider. + */ + private static boolean isExternalStorageDocument(Uri uri) { + return "com.android.externalstorage.documents".equals(uri.getAuthority()); + } + + /** + * @param uri The Uri to check. + * @return Whether the Uri authority is DownloadsProvider. + */ + private static boolean isDownloadsDocument(Uri uri) { + return "com.android.providers.downloads.documents".equals(uri.getAuthority()); + } + + /** + * @param uri The Uri to check. + * @return Whether the Uri authority is MediaProvider. + */ + private static boolean isMediaDocument(Uri uri) { + return "com.android.providers.media.documents".equals(uri.getAuthority()); + } +} diff --git a/app/src/main/java/com/gh/common/view/AdBannerView.kt b/app/src/main/java/com/gh/common/view/AdBannerView.kt index 89513c5bec..2db62805f0 100644 --- a/app/src/main/java/com/gh/common/view/AdBannerView.kt +++ b/app/src/main/java/com/gh/common/view/AdBannerView.kt @@ -8,7 +8,9 @@ import android.widget.LinearLayout import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView import androidx.viewpager2.widget.ViewPager2 +import com.facebook.drawee.view.SimpleDraweeView import com.gh.common.util.DisplayUtils +import com.gh.common.util.ImageUtils import com.gh.common.util.rxTimer import com.gh.gamecenter.R import com.gh.gamecenter.entity.SettingsEntity @@ -188,8 +190,10 @@ class AdBannerView : LinearLayout { override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { val ad = mDatas[position % mDatas.size] - val view = holder.itemView as ImageView - Picasso.with(context).load(ad.image).into(view) +// val view = holder.itemView as ImageView +// Picasso.with(context).load(ad.image).into(view) + val view = holder.itemView as SimpleDraweeView + ImageUtils.display(view, ad.image) holder.itemView.setOnClickListener { onItemClick?.invoke(position % mDatas.size) } diff --git a/app/src/main/java/com/gh/gamecenter/game/upload/GameUploadFragment.kt b/app/src/main/java/com/gh/gamecenter/game/upload/GameUploadFragment.kt index f1c30232b2..0ff3956184 100644 --- a/app/src/main/java/com/gh/gamecenter/game/upload/GameUploadFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/game/upload/GameUploadFragment.kt @@ -7,28 +7,30 @@ import android.provider.MediaStore import android.text.* import android.text.method.LinkMovementMethod import android.text.style.ClickableSpan +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import android.view.Window import android.widget.EditText import android.widget.ProgressBar +import android.widget.TextView import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView import com.gh.base.OnListClickListener import com.gh.common.constant.Config -import com.gh.common.util.DialogUtils -import com.gh.common.util.DirectUtils -import com.gh.common.util.GsonUtils -import com.gh.common.util.UploadImageUtils +import com.gh.common.util.* +import com.gh.gamecenter.CropImageActivity import com.gh.gamecenter.R -import com.gh.gamecenter.SuggestionActivity.MEDIA_STORE_REQUEST import com.gh.gamecenter.WebActivity import com.gh.gamecenter.entity.InstallGameEntity import com.gh.gamecenter.normal.NormalFragment import com.gh.gamecenter.suggest.SuggestPicAdapter import com.gh.gamecenter.suggest.SuggestSelectGameAdapter +import com.google.android.flexbox.FlexboxLayout import com.halo.assistant.HaloApp +import com.lightgame.utils.Util_System_Keyboard import com.lightgame.utils.Utils import io.reactivex.disposables.Disposable import kotlinx.android.synthetic.main.fragment_game_upload.* @@ -36,6 +38,7 @@ import okhttp3.MediaType import okhttp3.RequestBody import java.io.File import java.util.* +import java.util.concurrent.atomic.AtomicBoolean import kotlin.collections.ArrayList import kotlin.collections.HashMap import kotlin.collections.component1 @@ -45,12 +48,19 @@ import kotlin.collections.set class GameUploadFragment : NormalFragment() { private var mAdapter: SuggestPicAdapter? = null - private var selectGameDialog: Dialog? = null - private lateinit var gameEntity: InstallGameEntity - private lateinit var uploadDialog: UploadScheduleDialog + private var mIconAdapter: SuggestPicAdapter? = null + private var mSelectGameDialog: Dialog? = null + private lateinit var mInstallGameEntity: InstallGameEntity + private lateinit var mUploadDialog: UploadScheduleDialog private lateinit var mViewModel: GameUploadViewModel - private var disposable: Disposable? = null - val pathMap = LinkedHashMap() + private var mDisposable: Disposable? = null + private var mUploadFileDisposable: Disposable? = null + private val mPathMap = LinkedHashMap() + private lateinit var mIsOnline: AtomicBoolean//是否需要联网 + private var mGameLanguage: String = ""//游戏语言 + private var mGameType: String = ""//游戏类型 + private val mTags = arrayListOf()//游戏标签 + private var mApkUrl: String = "" override fun getLayoutId(): Int = R.layout.fragment_game_upload @@ -62,14 +72,23 @@ class GameUploadFragment : NormalFragment() { mViewModel = ViewModelProviders.of(this, factory).get(GameUploadViewModel::class.java) mViewModel.upLoadSuccess.observe(this, Observer { if (it) { - uploadDialog.uploadSuccess(true) + toast("感谢您的分享") + mUploadDialog.dismiss() + requireActivity().finish() } }) - tv_installation_package.text = Html.fromHtml(getString(R.string.upload_game_pkg)) - tv_game_name.text = Html.fromHtml(getString(R.string.suggestion_game_name)) - tv_game_intro.text = Html.fromHtml(getString(R.string.upload_game_intro)) - tv_screenshot.text = Html.fromHtml(getString(R.string.upload_game_pic)) + gameLabelTv.text = getString(R.string.upload_game_label).fromHtml() + gameDeveloperWordsTv.text = getString(R.string.upload_game_developer_words).fromHtml() + gameSourceTv.text = getString(R.string.upload_game_source).fromHtml() + gameTypeTv.text = getString(R.string.upload_game_type).fromHtml() + gameLanguageTv.text = getString(R.string.upload_game_language).fromHtml() + gameIsNetworkingTv.text = getString(R.string.upload_game_is_networking).fromHtml() + gameIconTitleTv.text = getString(R.string.upload_game_icon).fromHtml() + tv_installation_package.text = getString(R.string.upload_game_pkg).fromHtml() + tv_game_name.text = getString(R.string.suggestion_game_name).fromHtml() + tv_game_intro.text = getString(R.string.upload_game_intro).fromHtml() + tv_screenshot.text = getString(R.string.upload_game_pic).fromHtml() rv_screenshot.apply { layoutManager = object : GridLayoutManager(context, 5) { @@ -86,6 +105,21 @@ class GameUploadFragment : NormalFragment() { adapter = mAdapter } + gameIconRv.apply { + layoutManager = object : GridLayoutManager(context, 5) { + override fun canScrollVertically(): Boolean { + return false + } + } + mIconAdapter = SuggestPicAdapter(context, 1, object : OnListClickListener { + override fun onListClick(view: View?, position: Int, data: T) { + val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI) + startActivityForResult(intent, MEDIA_ICON_STORE_REQUEST) + } + }) + adapter = mIconAdapter + } + val privacyContent = SpannableStringBuilder("上传游戏即表示,您已阅读并同意《用户协议》与《游戏上传服务准则》") privacyContent.setSpan(object : ClickableSpan() { @@ -121,81 +155,150 @@ class GameUploadFragment : NormalFragment() { private fun initListener() { - tv_choose.setOnClickListener { + chooseGameLl.setOnClickListener { showSelectDialog() } + gameIsNetworkingRg.setOnCheckedChangeListener { group, checkedId -> + when (checkedId) { + R.id.gameNetworkingRb -> mIsOnline = AtomicBoolean(true) + R.id.gameNoNetworkingRb -> mIsOnline = AtomicBoolean(false) + } + } + gameLanguageRg.setOnCheckedChangeListener { group, checkedId -> + when (checkedId) { + R.id.gameLanguageChineseRb -> mGameLanguage = "中文" + R.id.gameLanguageEnglishRb -> mGameLanguage = "英文" + R.id.gameLanguageOtherRb -> mGameLanguage = "其他" + } + } + gameTypeRg.setOnCheckedChangeListener { group, checkedId -> + when (checkedId) { + R.id.gameTypeLocalRb -> mGameType = "local" + R.id.gameTypeOnlineRb -> mGameType = "online" + R.id.gameTypeOtherRb -> mGameType = "other" + } + } + + addGameLabeTv.setOnClickListener { + if (mTags.size < 5) { + showAddTagDialog() + } else { + toast("游戏标签最多添加5个") + } + } suggest_post_btn.setOnClickListener { - if (TextUtils.isEmpty(tv_choose.text.toString())) { - toast("请先选择游戏安装包") - return@setOnClickListener - } - if (TextUtils.isEmpty(et_game_name.text.toString())) { - toast("请先填写游戏名字") - return@setOnClickListener - } - if (TextUtils.isEmpty(et_game_intro.text.toString())) { - toast("请先填写介绍说明") - return@setOnClickListener - } - if (mAdapter!!.fileList.size == 0) { - toast("请先选择游戏截图") - return@setOnClickListener - } - if (!::uploadDialog.isInitialized) { - uploadDialog = UploadScheduleDialog() - } - uploadDialog.onClickListener = { - when (it) { - 0 -> { - //暂停上传 - disposable?.dispose() - uploadDialog.isDisable = true + commit() + } + } - DialogUtils.showAlertDialog(context, "提示", - "游戏上传中,确定要退出上传吗?", "不了", "确定", { - uploadDialog.isDisable = false - upload(getFileList()) - }, { - uploadDialog.dismiss() - activity?.finish() + private fun commit() { + if (TextUtils.isEmpty(tv_choose.text.toString())) { + toast("请先选择游戏安装包") + return + } + if (mIconAdapter!!.fileList.size == 0) { + toast("请先选择游戏图标") + return + } + if (TextUtils.isEmpty(et_game_name.text.toString())) { + toast("请先填写游戏名字") + return + } + if (!::mIsOnline.isInitialized) { + toast("请先选择游戏网络状态") + return + } + if (mGameLanguage.isEmpty()) { + toast("请先选择游戏语言") + return + } + if (mGameType.isEmpty()) { + toast("请先选择游戏类型") + return + } + if (TextUtils.isEmpty(gameSourceEt.text.toString())) { + toast("请填写游戏来源") + return + } + if (mTags.isEmpty()) { + toast("请先填写游戏标签") + return + } + if (TextUtils.isEmpty(et_game_intro.text.toString())) { + toast("请先填写游戏简介") + return + } + if (TextUtils.isEmpty(gameDeveloperWordsTv.text.toString())) { + toast("请先填写开发者的话") + return + } + if (mAdapter!!.fileList.size == 0) { + toast("请先选择游戏截图") + return + } + if (!::mUploadDialog.isInitialized) { + mUploadDialog = UploadScheduleDialog() + } + mUploadDialog.onClickListener = { + when (it) { + 0 -> { + //暂停上传 + mDisposable?.dispose() + mUploadFileDisposable?.dispose() + mUploadDialog.isDisable = true - }) - } - 1 -> { - uploadDialog.dismiss() - activity?.finish() - } - 2 -> { - DirectUtils.directToQqConversation(context!!, qqNumber = Config.getSettings()?.support?.qq) - } + DialogUtils.showAlertDialog(requireContext(), "提示", + "游戏上传中,确定要退出上传吗?", "不了", "确定", { + mUploadDialog.isDisable = false + if (mApkUrl.isEmpty()) { + uploadApk(mInstallGameEntity.gamePath ?: "") + } else { + uploadPicture(getFileList()) + } + }, { + mUploadDialog.dismiss() +// activity?.finish() + + }) + } + 1 -> { + mUploadDialog.dismiss() + activity?.finish() + } + 2 -> { + DirectUtils.directToQqConversation(requireContext(), qqNumber = Config.getSettings()?.support?.qq) } } - uploadDialog.show(childFragmentManager, "upload") - - upload(getFileList()) } + mUploadDialog.show(childFragmentManager, "upload") + + uploadApk(mInstallGameEntity.gamePath ?: "") } //获取未上传图片 private fun getFileList(): List { val fileList = arrayListOf() - if (pathMap.isEmpty()) return mAdapter!!.fileList + fileList.addAll(mIconAdapter!!.fileList) fileList.addAll(mAdapter!!.fileList) - for ((key, _) in pathMap) { + if (mPathMap.isEmpty()) { + return fileList + } + fileList.addAll(mAdapter!!.fileList) + for ((key, _) in mPathMap) { fileList.remove(key) } return fileList } //上传图片 - private fun upload(fileList: List) { + private fun uploadPicture(fileList: List) { if (fileList.isEmpty()) return - disposable = UploadImageUtils.uploadImageListOneByOne(UploadImageUtils.UploadType.game_upload, fileList, false, + mDisposable = UploadImageUtils.uploadImageListOneByOne(UploadImageUtils.UploadType.game_upload, fileList, false, object : UploadImageUtils.OnUploadImageListCountListener { override fun onSuccess(map: Map) { - pathMap.putAll(map) - val progress = 360 / mAdapter!!.fileList.size * pathMap.size - uploadDialog.updateProgress(progress) + mPathMap.putAll(map) + val progress = 360 / (mIconAdapter!!.fileList.size + mAdapter!!.fileList.size + 1) * (mPathMap.size + 1) + mUploadDialog.updateProgress(progress) } override fun onFinish() { @@ -203,23 +306,58 @@ class GameUploadFragment : NormalFragment() { } override fun onError() { - + mPathMap.clear() + mUploadDialog.uploadFail() } }) } + //上传apk + private fun uploadApk(apkPath: String) { + mUploadFileDisposable = OssUploadUtils.uploadFile(apkPath, OssUploadUtils.UploadType.GAME, object : OssUploadUtils.OnUploadFileListener { + override fun onSuccess(url: String) { + mApkUrl = url + val progress = 360 / (mIconAdapter!!.fileList.size + mAdapter!!.fileList.size + 1) + mUploadDialog.updateProgress(progress) + uploadPicture(getFileList()) + } + + override fun onError(e: Throwable?) { + mUploadDialog.uploadFail() + } + }) + } + //上传游戏 private fun uploadGames() { val imageList = ArrayList() - for ((_, value) in pathMap) { - imageList.add(value) + var index = 0 + var mGameIcon = "" + for ((_, value) in mPathMap) { + if (index == 0) { + mGameIcon = value + } else { + imageList.add(value) + } + index++ } val requestMap = HashMap() + requestMap["icon"] = mGameIcon + requestMap["is_online"] = mIsOnline.get() + requestMap["language"] = mGameLanguage + requestMap["package_url"] = mApkUrl + requestMap["type"] = mGameType + requestMap["tags"] = mTags + requestMap["source"] = gameSourceEt.text.toString() + requestMap["developer_say"] = gameDeveloperWordsTv.text.toString() requestMap["package_name"] = tv_choose.text.toString() - requestMap["size"] = gameEntity.gameSize + requestMap["size"] = mInstallGameEntity.gameSize requestMap["name"] = et_game_name.text.toString() requestMap["des"] = et_game_intro.text.toString() requestMap["images"] = imageList + if (gameVideoPathEt.text.toString().isNotEmpty()) { + requestMap["video"] = gameVideoPathEt.text.toString() + } val body = RequestBody.create(MediaType.parse("application/json"), GsonUtils.toJson(requestMap)) @@ -232,53 +370,47 @@ class GameUploadFragment : NormalFragment() { val recyclerView = view.findViewById(R.id.dialog_suggest_game_rv) val back = view.findViewById(R.id.dialog_suggest_game_back) val pb = view.findViewById(R.id.dialog_suggest_game_load) - val manualBtn = view.findViewById(R.id.dialog_suggest_manual) - val manualContainer = view.findViewById(R.id.dialog_suggest_manual_container) - val manualConfirm = view.findViewById(R.id.dialog_suggest_confirm) - val manualEdit = view.findViewById(R.id.dialog_suggest_edit) + val manualBtn = view.findViewById(R.id.dialog_suggest_manual) recyclerView.layoutManager = GridLayoutManager(context, 4) recyclerView.adapter = SuggestSelectGameAdapter(this@GameUploadFragment, pb) + manualBtn.text = "从设备上选择" - selectGameDialog = Dialog(context) - selectGameDialog?.apply { + mSelectGameDialog = Dialog(context) + mSelectGameDialog?.apply { requestWindowFeature(Window.FEATURE_NO_TITLE) setCanceledOnTouchOutside(false) setContentView(view) show() } - back.setOnClickListener { selectGameDialog?.cancel() } + back.setOnClickListener { mSelectGameDialog?.cancel() } manualBtn.setOnClickListener { - manualContainer.visibility = View.VISIBLE - manualBtn.visibility = View.GONE - } - manualConfirm.setOnClickListener { v -> - val gameName = manualEdit.text.toString() - if (!TextUtils.isEmpty(gameName)) { - loadDone(gameName) - } else { - toast("请输入游戏名字") - } + val intent = Intent(Intent.ACTION_GET_CONTENT) + intent.type = "*/*" + intent.addCategory(Intent.CATEGORY_OPENABLE) + startActivityForResult(intent, MEDIA_APK_STORE_REQUEST) } } override fun loadDone(obj: Any?) { super.loadDone(obj) - selectGameDialog?.cancel() + mSelectGameDialog?.cancel() if (obj is InstallGameEntity) run { - gameEntity = obj - tv_choose.background = null - tv_choose.text = "${gameEntity.packageName}.apk" + mInstallGameEntity = obj + chooseGameLl.background = null + chooseGameIconIv.visibility = View.GONE + tv_choose.text = "${mInstallGameEntity.packageName}.apk" } } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) - if (data != null && requestCode == MEDIA_STORE_REQUEST) { + if (data == null) return + if (requestCode == MEDIA_STORE_REQUEST || requestCode == MEDIA_ICON_STORE_REQUEST) { val selectedImage = data.data ?: return val filePathColumn = arrayOf(MediaStore.Images.Media.DATA) - val cursor = context!!.contentResolver.query(selectedImage, filePathColumn, null, null, null) + val cursor = requireContext().contentResolver.query(selectedImage, filePathColumn, null, null, null) ?: return cursor.moveToFirst() @@ -291,14 +423,55 @@ class GameUploadFragment : NormalFragment() { try { val file = File(picturePath) if (file.length() > 5 * 1024 * 1024) { - Utils.toast(context!!, getString(R.string.pic_max_hint, 5)) + Utils.toast(requireContext(), getString(R.string.pic_max_hint, 5)) } else { - mAdapter!!.addFileList(picturePath) + if (requestCode == MEDIA_STORE_REQUEST) { + // skip image crop + val intent = CropImageActivity.getIntent(requireContext(), picturePath, 9 / 16F, mEntrance) + startActivityForResult(intent, REQUEST_CODE_IMAGE_CROP) + } else { + val intent = CropImageActivity.getIntent(requireContext(), picturePath, 1F, mEntrance) + startActivityForResult(intent, REQUEST_CODE_ICON_IMAGE_CROP) + } } } catch (e: Exception) { Utils.toast(context, e.message) } - + } else if (requestCode == REQUEST_CODE_IMAGE_CROP || requestCode == REQUEST_CODE_ICON_IMAGE_CROP) { + val imagePath = data.getStringExtra(CropImageActivity.RESULT_CLIP_PATH) + if (requestCode == REQUEST_CODE_IMAGE_CROP) { + mAdapter!!.addFileList(imagePath) + } else { + mIconAdapter!!.addFileList(imagePath) + } + } else if (requestCode == MEDIA_APK_STORE_REQUEST) { + val uri = data.data ?: return + val apkPath = UriUtils.getPath(requireContext(), uri) + if (apkPath.isNotEmpty()) { + if (!apkPath.endsWith(".apk")) { + Utils.toast(requireContext(), "请选择正确的安装包") + return + } + mSelectGameDialog?.cancel() + try { + val file = File(apkPath) + if (file.length() > 5 * 1024 * 1024 * 1024) { + Utils.toast(requireContext(), getString(R.string.apk_max_size_hint, 5)) + } else { + val packageName = PackageUtils.getPackageNameByPath(requireContext(), apkPath) + mInstallGameEntity = InstallGameEntity().apply { + this.packageName = packageName + this.gameSize = File(apkPath).length() + this.gamePath = apkPath + } + chooseGameLl.background = null + chooseGameIconIv.visibility = View.GONE + tv_choose.text = "${packageName}.apk" + } + } catch (e: Exception) { + Utils.toast(requireContext(), e.message) + } + } } } @@ -315,4 +488,66 @@ class GameUploadFragment : NormalFragment() { } return super.onBackPressed() } + + private fun showAddTagDialog() { + val dialog = Dialog(requireContext()) + val view = View.inflate(context, R.layout.dialog_modify_nickname, null) + val title = view.findViewById(R.id.dialog_nickname_title) + val input = view.findViewById(R.id.dialog_nickname_input) + title.text = "新建标签" + input.hint = "" + input.setSelection(input.text.length) + input.filters = arrayOf(TextHelper.getFilter(6, "标签最多6个字")) + // 取消按钮 + view.findViewById(R.id.dialog_nickname_cancel).setOnClickListener { dialog.dismiss() } + // 确定按钮 + view.findViewById(R.id.dialog_nickname_confirm).setOnClickListener { + if (!TextUtils.isEmpty(input.text.toString().trim())) { + addTag(input.text.toString().trim()) + Util_System_Keyboard.hideSoftKeyboard(context, input) + dialog.dismiss() + } else { + toast(R.string.vote_empty_hint) + } + } + dialog.setOnDismissListener { + Util_System_Keyboard.hideSoftKeyboard(activity) + } + dialog.setCancelable(false) + dialog.requestWindowFeature(Window.FEATURE_NO_TITLE) + dialog.setContentView(view) + dialog.show() + mBaseHandler.postDelayed({ Util_System_Keyboard.showSoftKeyboard(context, input) }, 300) + } + + private fun addTag(tag: String) { + if (!mTags.contains(tag)) { + val labelView = LayoutInflater.from(requireContext()).inflate(R.layout.item_game_upload_label, null, false) + val params = FlexboxLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) + params.setMargins(0, 0, 8F.dip2px(), 0) + labelView.layoutParams = params + val labelTv = labelView.findViewById(R.id.labelTv) + labelTv.text = tag + labelView.findViewById(R.id.picDelIv).setOnClickListener { + gameLabelFl.removeView(labelView) + if (mTags.contains(tag)) { + mTags.remove(tag) + } + } + mTags.add(tag) + gameLabelFl.addView(labelView) + } else { + toast("标签已存在") + } + } + + + companion object { + const val MEDIA_STORE_REQUEST = 100 + const val MEDIA_ICON_STORE_REQUEST = 101 + const val MEDIA_APK_STORE_REQUEST = 102 + const val REQUEST_CODE_IMAGE_CROP = 103 + const val REQUEST_CODE_ICON_IMAGE_CROP = 104 + + } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/game/upload/UploadScheduleDialog.kt b/app/src/main/java/com/gh/gamecenter/game/upload/UploadScheduleDialog.kt index 5e37c52466..1e61a38eca 100644 --- a/app/src/main/java/com/gh/gamecenter/game/upload/UploadScheduleDialog.kt +++ b/app/src/main/java/com/gh/gamecenter/game/upload/UploadScheduleDialog.kt @@ -52,15 +52,26 @@ class UploadScheduleDialog : BaseDialogFragment() { /** * 上传成功(要显示上传失败) */ - fun uploadSuccess(isSuccess: Boolean) { + /*fun uploadSuccess(isSuccess: Boolean) { binding.isUploadSuccess = isSuccess - binding.ivUpload.setImageDrawable(ContextCompat.getDrawable(context!!, if (isSuccess) R.drawable.ic_upload_failure else R.drawable.ic_uploading)) + binding.ivUpload.setImageDrawable(ContextCompat.getDrawable(requireContext(), if (isSuccess) R.drawable.ic_upload_failure else R.drawable.ic_uploading)) binding.tvUpload.text = if (isSuccess) "游戏上传失败" else "游戏正在上传中" binding.circleProgressBar.isDisable(isSuccess) + binding.executePendingBindings() + }*/ + + fun uploadFail(){ + binding.isUploadSuccess = true + binding.ivUpload.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_upload_failure)) + binding.tvUpload.text = "游戏上传失败" + binding.circleProgressBar.isDisable(true) + binding.executePendingBindings() } + + override fun onBack(): Boolean { return true } 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 6f37fc214a..25aec0db7b 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 @@ -1989,6 +1989,9 @@ public interface ApiService { @GET("sts/oss?type=user") Single getOssUpdateConfig(); + @GET("sts/oss") + Single getOssUpdateConfig(@Query("type") String type); + /** * 获取视频标签 */ diff --git a/app/src/main/java/com/gh/gamecenter/suggest/SuggestPicAdapter.java b/app/src/main/java/com/gh/gamecenter/suggest/SuggestPicAdapter.java index 6bb37fec77..2edf94c4df 100644 --- a/app/src/main/java/com/gh/gamecenter/suggest/SuggestPicAdapter.java +++ b/app/src/main/java/com/gh/gamecenter/suggest/SuggestPicAdapter.java @@ -1,8 +1,6 @@ package com.gh.gamecenter.suggest; import android.content.Context; -import androidx.recyclerview.widget.RecyclerView; -import androidx.recyclerview.widget.RecyclerView.ViewHolder; import android.view.View; import android.view.ViewGroup; @@ -15,6 +13,9 @@ import com.lightgame.utils.Utils; import java.util.ArrayList; import java.util.List; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.RecyclerView.ViewHolder; + /** * Created by khy on 2017/3/31. */ @@ -22,6 +23,7 @@ public class SuggestPicAdapter extends BaseRecyclerAdapter { private OnListClickListener mListListener; private List picList; + private int maxSize = 5; public SuggestPicAdapter(Context context, OnListClickListener listListener) { super(context); @@ -29,6 +31,13 @@ public class SuggestPicAdapter extends BaseRecyclerAdapter { picList = new ArrayList<>(); } + public SuggestPicAdapter(Context context, int maxSize, OnListClickListener listListener) { + super(context); + this.mListListener = listListener; + picList = new ArrayList<>(); + this.maxSize = maxSize; + } + @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = mLayoutInflater.inflate(R.layout.suggest_pic_item, parent, false); @@ -40,7 +49,7 @@ public class SuggestPicAdapter extends BaseRecyclerAdapter { if (holder instanceof SuggestPicViewHolder) { SuggestPicViewHolder viewHolder = (SuggestPicViewHolder) holder; viewHolder.setClickData(picList); - if (position == getItemCount() - 1 && picList.size() < 5) { + if (position == getItemCount() - 1 && picList.size() < maxSize) { viewHolder.delete.setVisibility(View.GONE); ImageUtils.display(viewHolder.icon, R.drawable.suggest_add_pic_icon); } else { @@ -58,7 +67,7 @@ public class SuggestPicAdapter extends BaseRecyclerAdapter { @Override public int getItemCount() { // return picList.size() + 1; - return picList.size()<5?picList.size()+1:picList.size(); + return picList.size() < maxSize ? picList.size() + 1 : picList.size(); } public void addFileList(String picPath) { diff --git a/app/src/main/java/com/halo/assistant/HaloApp.java b/app/src/main/java/com/halo/assistant/HaloApp.java index 5f0455665f..b8ec16b29f 100644 --- a/app/src/main/java/com/halo/assistant/HaloApp.java +++ b/app/src/main/java/com/halo/assistant/HaloApp.java @@ -191,6 +191,7 @@ public class HaloApp extends TinkerAppLike { RxJavaPlugins.setErrorHandler(throwable -> { if (BuildConfig.DEBUG) { + Utils.log(throwable.toString()); Utils.toast(getApplication(), "当前页面未捕获的异常:" + throwable.toString()); } }); diff --git a/app/src/main/res/drawable-xxhdpi/ic_game_upload_add.png b/app/src/main/res/drawable-xxhdpi/ic_game_upload_add.png new file mode 100644 index 0000000000..54461c6544 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_game_upload_add.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_pic_delete.png b/app/src/main/res/drawable-xxhdpi/ic_pic_delete.png new file mode 100644 index 0000000000..9fbd8e6856 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_pic_delete.png differ diff --git a/app/src/main/res/drawable/border_999_bg.xml b/app/src/main/res/drawable/bg_border_blue_radius_4.xml similarity index 65% rename from app/src/main/res/drawable/border_999_bg.xml rename to app/src/main/res/drawable/bg_border_blue_radius_4.xml index 6ec721dab4..f07bb37d2d 100644 --- a/app/src/main/res/drawable/border_999_bg.xml +++ b/app/src/main/res/drawable/bg_border_blue_radius_4.xml @@ -3,10 +3,10 @@ android:shape = "rectangle" > + android:width = "0.5dp" + android:color = "@color/theme_font" /> - + diff --git a/app/src/main/res/layout/fragment_game_upload.xml b/app/src/main/res/layout/fragment_game_upload.xml index 67f321a623..6f9f5c2c97 100644 --- a/app/src/main/res/layout/fragment_game_upload.xml +++ b/app/src/main/res/layout/fragment_game_upload.xml @@ -1,13 +1,15 @@ + + + android:background="@android:color/white" + android:gravity="center_vertical"> + android:text="安装包*" + android:textColor="@color/text_333333" + android:textSize="14sp" /> + + + + + + + + + + + + - + android:id="@+id/gameIconTitleTv" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingLeft="20dp" + android:paddingTop="20dp" + android:paddingRight="20dp" + android:paddingBottom="14dp" + android:text="游戏图标*" + android:textColor="@color/text_333333" + android:textSize="14sp" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + + + + + + + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="@android:color/white" + android:gravity="center_vertical"> + android:paddingBottom="16dp" + android:text="游戏名字*" + android:textColor="@color/text_333333" + android:textSize="14sp" /> - + android:hint="请填写游戏名字 " + android:maxLength="20" + android:maxLines="1" + android:paddingTop="10dp" + android:paddingRight="10dp" + android:paddingBottom="10dp" + android:textColor="@color/text_666666" + android:textColorHint="@color/text_cccccc" + android:textCursorDrawable="@drawable/cursor_color" + android:textSize="12sp" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + android:paddingLeft="20dp" + android:paddingTop="16dp" + android:paddingRight="20dp" + android:paddingBottom="16dp" + android:text="游戏简介*" + android:textColor="@color/text_333333" + android:textSize="14sp" /> + android:textSize="12sp" /> - + + + android:gravity="top" + android:hint="请填写开发者的话" + android:lineSpacingMultiplier="1.2" + android:maxLength="1000" + android:minHeight="112dp" + android:paddingLeft="20dp" + android:paddingRight="20dp" + android:textColor="@color/text_666666" + android:textColorHint="@color/text_cccccc" + android:textSize="12sp" /> + + + + + + + + + + + + + + + + + + android:textSize="12sp" /> + android:id="@+id/suggest_post_ll" + android:layout_width="match_parent" + android:layout_height="60dp" + android:background="@android:color/white" + android:orientation="horizontal" + android:padding="10dp"> + android:id="@+id/suggest_post_btn" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@drawable/game_item_btn_download_style" + android:gravity="center" + android:text="@string/suggest_post" + android:textColor="@android:color/white" + android:textSize="14sp" /> - + \ No newline at end of file diff --git a/app/src/main/res/layout/item_ad_banner.xml b/app/src/main/res/layout/item_ad_banner.xml index 91ab3c7058..db443204ce 100644 --- a/app/src/main/res/layout/item_ad_banner.xml +++ b/app/src/main/res/layout/item_ad_banner.xml @@ -1,7 +1,15 @@ + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_game_upload_label.xml b/app/src/main/res/layout/item_game_upload_label.xml new file mode 100644 index 0000000000..d49c8d3568 --- /dev/null +++ b/app/src/main/res/layout/item_game_upload_label.xml @@ -0,0 +1,34 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3143c70896..ac08e47b0b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -462,6 +462,7 @@ 图片不能大于%1$dMB,请重新选择 + 安装包不能大于%1$dGB,请重新选择 http://www.ghzs.com/link?source=appshare100 http://www.ghzs.com/link?source=appshare300 http://image.ghzs666.com/pic/57d604808ab49e467d8b4568.png @@ -614,9 +615,16 @@ 功能需求*]]> 联系方式*]]> + 游戏标签*]]> + 开发者的话*]]> + 游戏来源*]]> + 游戏类型*]]> + 游戏语言*]]> + 是否联网*]]> + 游戏图标*]]> 安装包*]]> - 游戏介绍*]]> - 游戏截图*]]> + 游戏简介*]]> + 图片*]]> 所属游戏*]]> diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 0bd6ccff7c..f6aa0baf5a 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -300,4 +300,10 @@ + + \ No newline at end of file