From 0cf0870889d65f5d11d0b2c8af7bca9442a7ba19 Mon Sep 17 00:00:00 2001 From: cloudroam <cloudroam> Date: 星期一, 21 四月 2025 17:14:50 +0800 Subject: [PATCH] Merge branch 'master' of http://47.96.225.205:8888/r/FirstApp2 --- app/src/main/java/com/example/firstapp/ui/invitation/InvitationActivity.kt | 299 ++++++++++++++++++++++++++++++----------------------------- 1 files changed, 151 insertions(+), 148 deletions(-) diff --git a/app/src/main/java/com/example/firstapp/ui/invitation/InvitationActivity.kt b/app/src/main/java/com/example/firstapp/ui/invitation/InvitationActivity.kt index 353707d..9fb0021 100644 --- a/app/src/main/java/com/example/firstapp/ui/invitation/InvitationActivity.kt +++ b/app/src/main/java/com/example/firstapp/ui/invitation/InvitationActivity.kt @@ -1,9 +1,14 @@ package com.example.firstapp.ui.invitation +import android.app.Dialog import android.content.ClipData import android.content.ClipboardManager import android.content.Context import android.content.Intent +import android.graphics.Bitmap +import android.graphics.Color +import android.graphics.drawable.BitmapDrawable +import android.graphics.drawable.ColorDrawable import android.net.Uri import android.os.Bundle import android.os.Handler @@ -11,18 +16,34 @@ import android.text.Html import android.util.TypedValue import android.view.View +import android.view.ViewGroup import android.widget.Button +import android.widget.ImageView +import android.widget.LinearLayout import android.widget.TextView import android.widget.Toast import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.ContextCompat +import androidx.core.content.FileProvider +import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearSmoothScroller import androidx.recyclerview.widget.RecyclerView +import com.example.firstapp.App.Companion.context import com.example.firstapp.R import com.example.firstapp.adapter.InvitationAdapter +import com.example.firstapp.adapter.InvitationRecord2Adapter import com.example.firstapp.adapter.InvitationRecordAdapter +import com.example.firstapp.database.request.SmsLoginRequest +import com.example.firstapp.database.service.RetrofitClient import com.example.firstapp.entity.InvitationRecord +import com.example.firstapp.utils.Log import com.example.firstapp.utils.PreferencesManager +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.File +import java.io.FileOutputStream import kotlin.math.abs class InvitationActivity : AppCompatActivity() { @@ -30,14 +51,19 @@ private lateinit var recyclerSuccessView: RecyclerView private lateinit var recyclerRecordView: RecyclerView private lateinit var adapter: InvitationAdapter - private lateinit var recordadapter: InvitationRecordAdapter - private val data = mutableListOf<InvitationRecord>() - private val recorddata = mutableListOf<InvitationRecord>() +// private lateinit var recordadapter: InvitationRecordAdapter + private var data = mutableListOf<InvitationRecord>() + private var recorddata = mutableListOf<InvitationRecord>() private val handler = Handler(Looper.getMainLooper()) private val scrollInterval = 3000L private var currentScrollPosition = 0 private var currentRecordScrollPosition = 0 private var itemHeight = 0 // 动态存储item高度 + + private lateinit var invitedRecordRecyclerView2: RecyclerView + private lateinit var invitationAdapter: InvitationRecord2Adapter + + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -49,12 +75,10 @@ //初始化Adapter initSuccessAdapter() - initRecorddapter() +// initRecorddapter() //加载数据 - loadData() - - loadRecordData() + getInvitereward() //启动轮播 startAutoScroll() @@ -62,13 +86,12 @@ //分享 val btnInvite = findViewById<Button>(R.id.btnInvite) btnInvite.setOnClickListener { - shareImageToWechat() + showImagePreviewDialog() } //邀请码 val invitationCodeText = findViewById<TextView>(R.id.invitationCodeText) - invitationCodeText.text = "A1B2" - //invitationCodeText.text = formatInvitationCode(PreferencesManager.getInviteCode()); + invitationCodeText.text = formatInvitationCode(PreferencesManager.getInviteCode()); findViewById<Button>(R.id.copyButton).setOnClickListener { val clipboard = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager val clip = ClipData.newPlainText( @@ -78,90 +101,44 @@ clipboard.setPrimaryClip(clip) Toast.makeText(this, "已复制邀请码", Toast.LENGTH_SHORT).show() } + + } + private fun initViews() { findViewById<TextView>(R.id.tv_notic).apply { text = Html.fromHtml(getString(R.string.invite_reward_text), Html.FROM_HTML_MODE_LEGACY) } + + // 成功列表 recyclerSuccessView = findViewById(R.id.invitationsuccessRecyclerView) - addSuccessListener() - - recyclerRecordView = findViewById(R.id.invitationrecordRecyclerView) - addRecordListener() - } - - private fun addSuccessListener() { recyclerSuccessView.viewTreeObserver.addOnGlobalLayoutListener { if (recyclerSuccessView.childCount > 0) { - // 计算预期高度(60dp转px) val expectedHeight = dpToPx(60f) if (itemHeight != expectedHeight) { - // 修正所有item的高度 for (i in 0 until recyclerSuccessView.childCount) { recyclerSuccessView.getChildAt(i).layoutParams.height = expectedHeight } - // 请求重新布局 recyclerSuccessView.requestLayout() itemHeight = expectedHeight } } } - recyclerSuccessView.layoutManager = object : LinearLayoutManager(this@InvitationActivity) { - override fun onMeasure( - recycler: RecyclerView.Recycler, state: RecyclerView.State, - widthSpec: Int, heightSpec: Int - ) { - if (itemHeight > 0) { - // 使用实际测量的高度 - setMeasuredDimension( - View.resolveSize(widthSpec, width), - itemHeight - ) - } else { - // 默认高度60dp - val defaultHeight = TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, 60f, - resources.displayMetrics - ).toInt() - setMeasuredDimension( - View.resolveSize(widthSpec, width), - defaultHeight - ) - } - } - } - } - private fun addRecordListener() { - recyclerRecordView.viewTreeObserver.addOnGlobalLayoutListener { - if (recyclerSuccessView.childCount > 0) { - // 计算预期高度(60dp转px) - val expectedHeight = dpToPx(60f) - if (itemHeight != expectedHeight) { - // 修正所有item的高度 - for (i in 0 until recyclerSuccessView.childCount) { - recyclerSuccessView.getChildAt(i).layoutParams.height = expectedHeight - } - // 请求重新布局 - recyclerSuccessView.requestLayout() - itemHeight = expectedHeight - } - } - } - recyclerRecordView.layoutManager = object : LinearLayoutManager(this@InvitationActivity) { + + recyclerSuccessView.layoutManager = object : LinearLayoutManager(this) { override fun onMeasure( - recycler: RecyclerView.Recycler, state: RecyclerView.State, + recycler: RecyclerView.Recycler, + state: RecyclerView.State, widthSpec: Int, heightSpec: Int ) { if (itemHeight > 0) { - // 使用实际测量的高度 setMeasuredDimension( View.resolveSize(widthSpec, width), itemHeight ) } else { - // 默认高度60dp val defaultHeight = TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, 60f, resources.displayMetrics @@ -173,6 +150,9 @@ } } } + // 记录列表 +// recyclerRecordView = findViewById(R.id.invitationrecordRecyclerView) +// recyclerRecordView.layoutManager = LinearLayoutManager(this) } private fun initSuccessAdapter() { @@ -191,68 +171,131 @@ recyclerSuccessView.adapter = adapter } - private fun initRecorddapter() { - recordadapter = InvitationRecordAdapter(this, recorddata).apply { - registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() { - override fun onItemRangeInserted(positionStart: Int, itemCount: Int) { - // 数据插入时检查高度 - recyclerRecordView.post { - if (recyclerRecordView.childCount > 0) { - itemHeight = recyclerRecordView.getChildAt(0).height +// private fun initRecorddapter() { +// recordadapter = InvitationRecordAdapter(this, recorddata) +// recyclerRecordView.adapter = recordadapter +// } +// private fun initRecorddapter() { +// recordadapter = InvitationRecordAdapter(this, recorddata).apply { +// registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() { +// override fun onItemRangeInserted(positionStart: Int, itemCount: Int) { +// // 数据插入时检查高度 +// recyclerRecordView.post { +// if (recyclerRecordView.childCount > 0) { +// itemHeight = recyclerRecordView.getChildAt(0).height +// } +// } +// } +// }) +// } +// recyclerRecordView.adapter = recordadapter +// } + + private fun getInvitereward() { + lifecycleScope.launch { + try { + val response = RetrofitClient.apiService.getInvitereward() + if (response.code == "0") { + response.data?.let { records -> + // 正确更新现有列表(保持原有引用) + data.apply { + clear() + addAll(records.successInvite ?: emptyList()) } + + recorddata.apply { + clear() + addAll(records.myInvite ?: emptyList()) // 注意这里使用myInvite + } + + // 加载适配器 + invitedRecordRecyclerView2 = findViewById(R.id.invited_record_recycler_view_2) + invitedRecordRecyclerView2.layoutManager = LinearLayoutManager(this@InvitationActivity) + invitationAdapter = InvitationRecord2Adapter(records.myInvite) + invitedRecordRecyclerView2.adapter = invitationAdapter + + + // 在UI线程更新适配器 + withContext(Dispatchers.Main) { + adapter.notifyDataSetChanged() +// recordadapter.notifyDataSetChanged() + } + } ?: run { + Log.w("API", "Response data is null") } + } else { + Log.w("API", "Server error: ${response.msg}") } - }) + } catch (e: Exception) { + Log.e("getinviterewardError", "message: ${e.message}", e) + withContext(Dispatchers.Main) { + Toast.makeText(context, "请求失败: ${e.message}", Toast.LENGTH_SHORT).show() + } + } } - recyclerRecordView.adapter = recordadapter } - private fun loadData() { - data.clear() - data.addAll( - listOf( - InvitationRecord("H****e", "获得了1天会员", "已注册"), - InvitationRecord("U****r", "获得了2天会员", "已注册"), - InvitationRecord("A****e", "获得了免广告特权", "已注册"), - InvitationRecord("B****e", "获得了3天会员", "已注册"), - InvitationRecord("C****o", "获得了4天会员", "已注册") - ) - ) - adapter.notifyDataSetChanged() + private fun showImagePreviewDialog() { + val dialog = Dialog(this, android.R.style.Theme_Translucent_NoTitleBar).apply { + // 设置全屏+透明背景 + window?.apply { + setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) + setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + } + + setContentView(R.layout.dialog_image_preview) + setCancelable(true) // 点击空白处可关闭 + + val imageView = findViewById<ImageView>(R.id.ivPreview) + + // 长按分享(不关闭对话框) + imageView.setOnLongClickListener { + shareImageToWechat() + true + } + + // 点击图片关闭(可选) + imageView.setOnClickListener { + dismiss() + } + } + + dialog.show() } - private fun loadRecordData() { - recorddata.clear() - recorddata.addAll( - listOf( - InvitationRecord("M****e", "", "未注册"), - InvitationRecord("Q****r", "", "已注册"), - InvitationRecord("W****e", "", "未注册"), - InvitationRecord("E****e", "", "未注册"), - InvitationRecord("R****o", "", "已注册") - ) - ) - recordadapter.notifyDataSetChanged() - } // 分享资源图片到微信 private fun shareImageToWechat() { try { - // 获取资源图片的URI - val imageUri = Uri.parse("android.resource://${packageName}/${R.drawable.location}") + // 1. 将 drawable 图片保存到缓存目录 + val drawable = ContextCompat.getDrawable(this, R.drawable.invite)!! + val bitmap = (drawable as BitmapDrawable).bitmap + // 2. 创建临时图片文件 + val cacheDir = File(cacheDir, "shared_images").apply { mkdirs() } + val imageFile = File(cacheDir, "invite.jpg") // 指定文件名 + FileOutputStream(imageFile).use { out -> + bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out) + } + + // 3. 使用 FileProvider 获取 URI + val imageUri = FileProvider.getUriForFile( + this, + "${packageName}.fileprovider", + imageFile + ) + + // 4. 创建分享 Intent val intent = Intent().apply { action = Intent.ACTION_SEND - type = "image/*" + type = "image/jpeg" putExtra(Intent.EXTRA_STREAM, imageUri) flags = Intent.FLAG_GRANT_READ_URI_PERMISSION setPackage("com.tencent.mm") // 指定微信包名 } - // 创建选择器,即使微信不可用也能选择其他应用 + // 5. 启动分享选择器 val chooserIntent = Intent.createChooser(intent, "分享邀请图片") - - // 检查是否有应用能处理这个Intent if (intent.resolveActivity(packageManager) != null) { startActivity(chooserIntent) } else { @@ -264,8 +307,8 @@ } private fun formatInvitationCode(code: String): String { - return if (code.length > 2) { - code.chunked(2).joinToString(" ") + return if (code.length > 1) { + code.chunked(1).joinToString(" ") } else { code } @@ -280,7 +323,6 @@ // 使用取模运算确保位置在有效范围内 currentScrollPosition++ - currentRecordScrollPosition++ // 创建自定义平滑滚动器 val smoothScroller = object : LinearSmoothScroller(this@InvitationActivity) { @@ -305,32 +347,9 @@ targetPosition = currentScrollPosition } - val smoothRecordScroller = object : LinearSmoothScroller(this@InvitationActivity) { - override fun getVerticalSnapPreference(): Int = SNAP_TO_START - - override fun calculateDyToMakeVisible(view: View, snapPreference: Int): Int { - // 计算需要滚动的距离,确保完整显示下一个item - val top = view.top - val height = view.height - return when { - snapPreference == SNAP_TO_START -> -top - snapPreference == SNAP_TO_END -> -(top - (recyclerRecordView.height - height)) - else -> -(top - (recyclerRecordView.height / 2 - height / 2)) - } - } - - override fun calculateTimeForScrolling(dx: Int): Int { - // 根据滚动距离动态计算时间,保持匀速 - return maxOf((500f * abs(dx) / itemHeight).toInt(), 200) - } - }.apply { - targetPosition = currentRecordScrollPosition - } // 启动平滑滚动 recyclerSuccessView.layoutManager?.startSmoothScroll(smoothScroller) - - recyclerRecordView.layoutManager?.startSmoothScroll(smoothRecordScroller) // 更智能的边界检测 (recyclerSuccessView.layoutManager as? LinearLayoutManager)?.let { lm -> @@ -345,24 +364,8 @@ } } - (recyclerRecordView.layoutManager as? LinearLayoutManager)?.let { lm -> - val lastVisible = lm.findLastVisibleItemPosition() - val totalItems = recordadapter.itemCount - - // 当接近"虚拟列表"末尾时,跳转到中间位置 - if (lastVisible >= totalItems - 3) { - val jumpPosition = (totalItems / 2) * (Int.MAX_VALUE / totalItems) - currentRecordScrollPosition = jumpPosition - recyclerRecordView.scrollToPosition(jumpPosition) - } - } - handler.postDelayed(this, scrollInterval) } - } - - private fun pxToDp(px: Int, context: Context): Int { - return (px / (context.resources.displayMetrics.density)).toInt() } private fun dpToPx(dp: Float): Int { -- Gitblit v1.9.3