Compare commits

16 Commits
main ... dev

Author SHA1 Message Date
fengjignqi
4c11b3f9c3 去除WRITE_EXTERNAL_STORAGE权限 2026-08-15 11:01:14 +08:00
fengjignqi
577f49e032 更新版本 2026-08-15 10:53:36 +08:00
fengjignqi
a279230669 更新版本 2026-08-14 14:04:09 +08:00
fengjignqi
969338f3bd 优化 2026-08-14 08:50:25 +08:00
fengjignqi
c2dfa9145a 取消订单返回余额 2026-08-12 11:05:55 +08:00
fengjignqi
499673782c 接入微信支付,微信提现 2026-08-12 08:32:42 +08:00
fengjignqi
f3006f4255 接入微信支付 2026-08-10 15:41:43 +08:00
fengjignqi
579e9427c8 接入微信支付 2026-08-09 08:37:09 +08:00
fengjignqi
39dbe5f1e4 优化修改bug 2026-08-08 14:45:08 +08:00
fengjignqi
9806e66790 优化 2026-08-07 08:33:52 +08:00
fengjignqi
c6eeb1321c 优化 2026-08-05 15:00:34 +08:00
fengjignqi
9d432dba67 优化ai对话页面 2026-08-04 10:44:12 +08:00
fengjignqi
54dc0b5598 优化ai对话页面 2026-08-03 15:06:08 +08:00
fengjignqi
170936fd23 优化ai对话页面 2026-08-03 11:44:42 +08:00
fengjignqi
bc0c7adb41 优化ai对话页面,以及权限申请 2026-08-03 10:16:31 +08:00
fengjignqi
12fecfbe41 dev分支 2026-07-30 15:25:01 +08:00
129 changed files with 5051 additions and 3350 deletions

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -4,6 +4,13 @@
<selectionStates> <selectionStates>
<SelectionState runConfigName="app"> <SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" /> <option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2026-08-14T02:57:51.212958400Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="PhysicalDevice" identifier="serial=D122222104A9" />
</handle>
</Target>
</DropdownSelection>
<DialogSelection /> <DialogSelection />
</SelectionState> </SelectionState>
</selectionStates> </selectionStates>

13
.idea/deviceManager.xml generated Normal file
View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DeviceTable">
<option name="columnSorters">
<list>
<ColumnSorterState>
<option name="column" value="Name" />
<option name="order" value="ASCENDING" />
</ColumnSorterState>
</list>
</option>
</component>
</project>

View File

@@ -84,6 +84,8 @@ dependencies {
implementation libs.androidx.compose.material3 implementation libs.androidx.compose.material3
implementation libs.material implementation libs.material
implementation libs.appcompat implementation libs.appcompat
implementation libs.luban
implementation 'io.noties.markwon:core:4.6.2'
testImplementation libs.junit testImplementation libs.junit
androidTestImplementation libs.androidx.junit androidTestImplementation libs.androidx.junit
androidTestImplementation libs.androidx.espresso.core androidTestImplementation libs.androidx.espresso.core
@@ -156,4 +158,7 @@ dependencies {
implementation 'com.github.yyued:SVGAPlayer-Android:2.6.1' implementation 'com.github.yyued:SVGAPlayer-Android:2.6.1'
//圆形视图库
implementation 'com.makeramen:roundedimageview:2.3.0'
} }

View File

@@ -2,6 +2,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<application <application
android:name=".CKApp" android:name=".CKApp"
android:allowBackup="true" android:allowBackup="true"
@@ -29,10 +32,10 @@
</activity> </activity>
<activity <activity
android:name=".ui.act.welcome.WelcomeActivity" android:name=".ui.act.welcome.WelcomeActivity"
android:theme="@style/Theme.CkCollar_app.NoActionBar"></activity> android:theme="@style/Theme.CkCollar_app.NoActionBar"/>
<activity <activity
android:name=".ui.act.welcome.PermisstionActivity" android:name=".ui.act.welcome.PermisstionActivity"
android:theme="@style/Theme.CkCollar_app.NoActionBar"></activity> android:theme="@style/Theme.CkCollar_app.NoActionBar"/>
<activity <activity
android:name=".ui.act.login.LoginActivity" android:name=".ui.act.login.LoginActivity"
android:launchMode="singleTask" android:launchMode="singleTask"
@@ -53,6 +56,9 @@
<activity <activity
android:name=".ui.act.login.AgreementActivity" android:name=".ui.act.login.AgreementActivity"
android:theme="@style/Theme.CkCollar_app.NoActionBar"></activity> android:theme="@style/Theme.CkCollar_app.NoActionBar"></activity>
<activity
android:name=".ui.act.setting.SettingWebViewActivity"
android:theme="@style/Theme.CkCollar_app.NoActionBar"></activity>
<activity <activity
android:name=".ui.act.home.MainActivity" android:name=".ui.act.home.MainActivity"
android:launchMode="singleTask" android:launchMode="singleTask"
@@ -64,6 +70,12 @@
android:launchMode="singleTask" android:launchMode="singleTask"
android:taskAffinity="com.ck.ckcollar.app" android:taskAffinity="com.ck.ckcollar.app"
android:theme="@android:style/Theme.Translucent.NoTitleBar"></activity> android:theme="@android:style/Theme.Translucent.NoTitleBar"></activity>
<activity
android:name=".wxapi.WXPayEntryActivity"
android:exported="true"
android:launchMode="singleTop"
android:taskAffinity="com.ck.ckcollar.app"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
<activity <activity
android:name=".ui.act.petmanager.PetManagerActivity" android:name=".ui.act.petmanager.PetManagerActivity"
android:theme="@style/Theme.CkCollar_app.NoActionBar"></activity> android:theme="@style/Theme.CkCollar_app.NoActionBar"></activity>
@@ -269,7 +281,7 @@
<provider <provider
android:name="androidx.core.content.FileProvider" android:name="androidx.core.content.FileProvider"
android:authorities="com.ck.ckcollar.app.fileprovider" android:authorities="${applicationId}.fileprovider"
android:exported="false" android:exported="false"
android:grantUriPermissions="true"> android:grantUriPermissions="true">
<meta-data <meta-data
@@ -291,11 +303,10 @@
<uses-permission android:name="android.permission.INTERNET"></uses-permission> <uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<!-- <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />--> <!-- <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />-->
<!-- <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />--> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />--> <!-- <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />-->
<!-- <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />--> <!-- <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />-->
@@ -305,12 +316,12 @@
<!-- android:required="true" />--> <!-- android:required="true" />-->
<!-- &lt;!&ndash; 必要的蓝牙权限 &ndash;&gt;--> <!-- &lt;!&ndash; 必要的蓝牙权限 &ndash;&gt;-->
<!-- <uses-permission android:name="android.permission.BLUETOOTH" />--> <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<!-- <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />--> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
<!-- &lt;!&ndash; 从 Android 12 (API 31) 开始,需要新的蓝牙扫描/连接权限 &ndash;&gt;--> <!-- &lt;!&ndash; 从 Android 12 (API 31) 开始,需要新的蓝牙扫描/连接权限 &ndash;&gt;-->
<!-- <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />--> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<!-- <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />--> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />--> <!-- <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />-->

View File

@@ -22,6 +22,8 @@ class CKApp : Application() {
var activitys = mutableListOf<TTBaseActivity>() var activitys = mutableListOf<TTBaseActivity>()
lateinit var token : String lateinit var token : String
var isUserLoggedIn: Boolean = false
private set
var wxJump = 0 var wxJump = 0
var userInfo : UserInfoModel? = null var userInfo : UserInfoModel? = null
companion object { companion object {
@@ -33,7 +35,8 @@ class CKApp : Application() {
super.onCreate() super.onCreate()
app = this app = this
token = PreferencesUtils.getString(this, Const.TOKEN,"").toString() token = PreferencesUtils.getString(this, Const.TOKEN, "").orEmpty()
isUserLoggedIn = token.isNotBlank()
var userData = PreferencesUtils.getString(this, Const.USER_DATA,"").toString() var userData = PreferencesUtils.getString(this, Const.USER_DATA,"").toString()
if (!TextUtils.isEmpty(userData)){ if (!TextUtils.isEmpty(userData)){
userInfo = Gson().fromJson<UserInfoModel>(userData, UserInfoModel::class.java) userInfo = Gson().fromJson<UserInfoModel>(userData, UserInfoModel::class.java)
@@ -51,16 +54,31 @@ class CKApp : Application() {
Glide.init(this, GlideBuilder().setDefaultRequestOptions(defaultOptions)) Glide.init(this, GlideBuilder().setDefaultRequestOptions(defaultOptions))
//SkinManager.getInstance().init(this); //SkinManager.getInstance().init(this);
UMConfigure.setLogEnabled(true) // UMConfigure.setLogEnabled(true)
MobclickAgent.setPageCollectionMode(MobclickAgent.PageMode.MANUAL); // MobclickAgent.setPageCollectionMode(MobclickAgent.PageMode.MANUAL);
// UMConfigure.preInit(this, "6a618cf0e88ae439bf379f37", "UM");
UMConfigure.preInit(this, "6a618cf0e88ae439bf379f37", "UM"); // UMConfigure.init(this, "6a618cf0e88ae439bf379f37", "UM", UMConfigure.DEVICE_TYPE_PHONE, "");
UMConfigure.init(this, "6a618cf0e88ae439bf379f37", "UM", UMConfigure.DEVICE_TYPE_PHONE, "");
TTLog.isLogEable(true) TTLog.isLogEable(true)
} }
fun setLoginToken(value: String) {
token = value
isUserLoggedIn = value.isNotBlank()
PreferencesUtils.putString(this, Const.TOKEN, value)
if (isUserLoggedIn) {
PreferencesUtils.putBoolean(this, Const.FIRST, false)
}
}
fun clearLoginState() {
token = ""
userInfo = null
isUserLoggedIn = false
PreferencesUtils.putString(this, Const.TOKEN, "")
PreferencesUtils.putString(this, Const.USER_DATA, "")
PreferencesUtils.putString(this, Const.PET_DATA, "")
}
} }

View File

@@ -7,7 +7,10 @@ object ActionCode {
//const val BASE_URL = "https://ragged-parting-unrushed.ngrok-free.dev"; //const val BASE_URL = "https://ragged-parting-unrushed.ngrok-free.dev";
//const val BASE_URL = "https://ragged-parting-unrushed.ngrok-free.dev"; //const val BASE_URL = "https://ragged-parting-unrushed.ngrok-free.dev";
// const val BASE_URL = "https://ragged-parting-unrushed.ngrok-free.dev"; // const val BASE_URL = "https://ragged-parting-unrushed.ngrok-free.dev";
const val BASE_URL = "https://d.chongdunpet.com" const val BASE_URL = "https://d.chongdunpet.com"
// const val BASE_URL = "http://192.168.1.187:8080"
const val CUSTOMER_URL = "wss://d.chongdunpet.com/ws/chat?role=customer&token="; const val CUSTOMER_URL = "wss://d.chongdunpet.com/ws/chat?role=customer&token=";
@@ -152,6 +155,7 @@ object ActionCode {
"找回支付密码" -> url = "/app/setting/payPassword/reset" "找回支付密码" -> url = "/app/setting/payPassword/reset"
"查询支付密码状态" -> url = "/app/setting/payPassword/status" "查询支付密码状态" -> url = "/app/setting/payPassword/status"
"订单支付" -> url = "/app/order/pay" "订单支付" -> url = "/app/order/pay"
"取消待支付订单" -> url = "/app/order/cancelPending"
"修改个人信息" -> url = "/app/profile/update" "修改个人信息" -> url = "/app/profile/update"
@@ -175,6 +179,7 @@ object ActionCode {
"绑定微信" -> url = "/app/profile/wx/bind" "绑定微信" -> url = "/app/profile/wx/bind"
} }
TTLog.e(url) TTLog.e(url)
return url; return url;

View File

@@ -34,4 +34,9 @@ object Config : TileSourceFactory() {
override fun getTileURLString(pMapTileIndex: Long) = override fun getTileURLString(pMapTileIndex: Long) =
("$baseUrl&X=${MapTileIndex.getX(pMapTileIndex)}&Y=${MapTileIndex.getY(pMapTileIndex)}&L=${MapTileIndex.getZoom(pMapTileIndex)}") ("$baseUrl&X=${MapTileIndex.getX(pMapTileIndex)}&Y=${MapTileIndex.getY(pMapTileIndex)}&L=${MapTileIndex.getZoom(pMapTileIndex)}")
} }
//隐私政策
var PRIVACY_POLICY = "http://f.chongdunpet.com/privacy_policy.html#a6";
//三方SDK
var THIRD_PARTY_SDK = "http://h.chongdunpet.com/third_party_sdk.html";
} }

View File

@@ -1,6 +1,7 @@
package com.ck.ckcollar.app.model package com.ck.ckcollar.app.model
class BannarModel : CkBaseModel(){ class BannarModel : CkBaseModel(){
var localImageRes: Int = 0
var bannerStatus: String? = "" var bannerStatus: String? = ""
var bannerUrl: String? = "" var bannerUrl: String? = ""
var createBy: String? = "" var createBy: String? = ""

View File

@@ -10,6 +10,14 @@ class MemberModel {
var amount: Double = 0.0 // 金额 var amount: Double = 0.0 // 金额
var payType: String? = "" // 支付方式 var payType: String? = "" // 支付方式
var orderNo: String? = "" // 订单编号 var orderNo: String? = "" // 订单编号
var timeStamp: String? = null // 微信支付时间戳
var packageVal: String? = null // 微信支付扩展字段
var paySign: String? = null // 微信支付签名
var appId: String? = null // 微信 AppID
var partnerId: String? = null // 微信支付商户号
var prepayId: String? = null // 微信预支付订单号
var signType: String? = null // 签名类型
var nonceStr: String? = null // 随机字符串
var order: MemberOrder? = null // 订单信息 var order: MemberOrder? = null // 订单信息
class MemberOrder { class MemberOrder {

View File

@@ -0,0 +1,13 @@
package com.ck.ckcollar.app.model
import com.google.gson.JsonElement
class OrderPaymentModel {
var orderId: Int = 0
var orderStr: JsonElement? = null
var wxMap: JsonElement? = null
var pointsAmount: Double = 0.0
var balanceAmount: Double = 0.0
var alipayAmount: Double = 0.0
var info: String? = ""
}

View File

@@ -4,5 +4,13 @@ class PayOrderModel : CkBaseModel(){
var orderStr: String? = "" // 订单字符串 var orderStr: String? = "" // 订单字符串
var amount: String? = "" // 金额 var amount: String? = "" // 金额
var orderNo: String? = "" // 订单编号 var orderNo: String? = "" // 订单编号
var timeStamp: String? = null // 微信支付时间戳
var packageVal: String? = null // 微信支付扩展字段
var paySign: String? = null // 微信支付签名
var appId: String? = null // 微信 AppID
var partnerId: String? = null // 微信支付商户号
var prepayId: String? = null // 微信预支付订单号
var signType: String? = null // 签名类型
var nonceStr: String? = null // 随机字符串
var info : String? = "" var info : String? = ""
} }

View File

@@ -1,7 +1,22 @@
package com.ck.ckcollar.app.model package com.ck.ckcollar.app.model
class RechargeModel { class RechargeModel {
// Alipay
var orderStr: String? = null var orderStr: String? = null
// Common
var amount: Double? = null var amount: Double? = null
var orderNo: String? = null
// WeChat Pay
var timeStamp: String? = null
var packageVal: String? = null
var paySign: String? = null
var appId: String? = null
var partnerId: String? = null
var prepayId: String? = null
var signType: String? = null
var nonceStr: String? = null
var RC1782974779440000002 : String? = null var RC1782974779440000002 : String? = null
} }

View File

@@ -1,11 +1,10 @@
package com.ck.ckcollar.app.model package com.ck.ckcollar.app.model
class UpdateModel : CkBaseModel(){ class UpdateModel : CkBaseModel(){
//{"androidVersion":1,"content":"","iosVersion":1,"isForce":false}
var androidVersion : Int = 0
var iosVersion : Int = 0
var isForce : Boolean = false
var content: String? = "" var content: String? = ""
var downloadUrl: String? = ""
var hasUpdate: Boolean = false
var isForce: Boolean = false
var versionCode: Int = 0
var versionName: String? = ""
} }

View File

@@ -4,4 +4,10 @@ class WithDrawModel {
var amount :String? = "" var amount :String? = ""
var payMethod :String? = "" var payMethod :String? = ""
var authPackageInfo :String? = null
var thirdOrderNo :String? = null
var outBillNo :String? = null
var mchId :String? = null
var appId :String? = null
var needConfirm :Boolean = false
} }

View File

@@ -29,7 +29,11 @@ import pub.devrel.easypermissions.EasyPermissions.PermissionCallbacks
class BlueToothActivity : CKBaseActivity() , PermissionCallbacks{ class BlueToothActivity : CKBaseActivity() , PermissionCallbacks{
lateinit var activityBluetoothBinding: ActivityBluetoothBinding lateinit var activityBluetoothBinding: ActivityBluetoothBinding
val permissions = listOf(Manifest.permission.BLUETOOTH,Manifest.permission.BLUETOOTH_ADMIN,Manifest.permission.BLUETOOTH_SCAN,Manifest.permission.BLUETOOTH_CONNECT) val permissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
listOf(Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT)
} else {
listOf(Manifest.permission.ACCESS_FINE_LOCATION)
}
lateinit var blueBoothAdapter: BlueBoothAdapter lateinit var blueBoothAdapter: BlueBoothAdapter
var devices = mutableListOf<String>() var devices = mutableListOf<String>()
@@ -185,7 +189,17 @@ class BlueToothActivity : CKBaseActivity() , PermissionCallbacks{
requestCode: Int, requestCode: Int,
perms: List<String?> perms: List<String?>
) { ) {
val deniedPermissions = perms.filterNotNull().toTypedArray()
val permanentlyDenied = deniedPermissions.any {
!ActivityCompat.shouldShowRequestPermissionRationale(this, it)
}
if (permanentlyDenied) {
super.onPermissionsDenied(requestCode, deniedPermissions, true)
}
}
override fun onPermissionsGranted(requestCode: Int, permissions: Array<String>) {
initData()
} }
class BlueBoothAdapter(var context: CKBaseActivity, var scanResults: List<String>) : RecyclerView.Adapter<BlueBoothAdapter.BlueBoothHolder>() { class BlueBoothAdapter(var context: CKBaseActivity, var scanResults: List<String>) : RecyclerView.Adapter<BlueBoothAdapter.BlueBoothHolder>() {

View File

@@ -143,7 +143,17 @@ class WifiListActivity : CKBaseActivity(), PermissionCallbacks {
requestCode: Int, requestCode: Int,
perms: List<String?> perms: List<String?>
) { ) {
val deniedPermissions = perms.filterNotNull().toTypedArray()
val permanentlyDenied = deniedPermissions.any {
!ActivityCompat.shouldShowRequestPermissionRationale(this, it)
}
if (permanentlyDenied) {
super.onPermissionsDenied(requestCode, deniedPermissions, true)
}
}
override fun onPermissionsGranted(requestCode: Int, permissions: Array<String>) {
initData()
} }
class WifiAdapter(var context: CKBaseActivity, var scanResults: List<ScanResult>) : RecyclerView.Adapter<WifiAdapter.WifiiewHoldr>() { class WifiAdapter(var context: CKBaseActivity, var scanResults: List<ScanResult>) : RecyclerView.Adapter<WifiAdapter.WifiiewHoldr>() {

View File

@@ -39,6 +39,8 @@ import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
class BalanceActivity : CKLHBaseActionBarActivity() , View.OnClickListener{ class BalanceActivity : CKLHBaseActionBarActivity() , View.OnClickListener{
override val shouldRequestPermissionsOnCreate: Boolean = false
lateinit var binding: ActivityBalanceBinding lateinit var binding: ActivityBalanceBinding
var data = listOf<RecordModel>() var data = listOf<RecordModel>()
lateinit var adapter: RecordAdapter lateinit var adapter: RecordAdapter
@@ -116,9 +118,16 @@ class BalanceActivity : CKLHBaseActionBarActivity() , View.OnClickListener{
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
getBalanceInfo() showProgeassDialog()
var pendingRequests = 2
getList() val onRequestFinished = {
pendingRequests--
if (pendingRequests == 0) {
hiddenProgeassDialog()
}
}
getBalanceInfo(onRequestFinished)
getList(onRequestFinished)
} }
override fun getResult(data: DataCollection, resultCode: Int) { override fun getResult(data: DataCollection, resultCode: Int) {
if (resultCode == 1001){ if (resultCode == 1001){
@@ -127,22 +136,24 @@ class BalanceActivity : CKLHBaseActionBarActivity() , View.OnClickListener{
getList() getList()
} }
} }
fun getBalanceInfo(){ fun getBalanceInfo(onFinished: (() -> Unit)? = null){
TTHttpClient.get(this,"余额", TTRequestParam(),object : ICallback{ TTHttpClient.get(this,"余额", TTRequestParam(),object : ICallback{
override fun onSuccess(data: String) { override fun onSuccess(data: String) {
model = Gson().fromJson<BalanceModle>(data, BalanceModle::class.java) model = Gson().fromJson<BalanceModle>(data, BalanceModle::class.java)
binding.textBalance.text = model?.balance.toString() binding.textBalance.text = model?.balance.toString()
onFinished?.invoke()
} }
override fun onFailed(code: String, msg: String) { override fun onFailed(code: String, msg: String) {
onFinished?.invoke()
toast(msg) toast(msg)
} }
}) })
} }
fun getList(){ fun getList(onFinished: (() -> Unit)? = null){
TTHttpClient.get(this,"余额明细列表", TTRequestParam().apply { add(TTRequestData("type",type)) TTHttpClient.get(this,"余额明细列表", TTRequestParam().apply { add(TTRequestData("type",type))
add(TTRequestData("month",""))},object : ICallback{ add(TTRequestData("month",""))},object : ICallback{
override fun onSuccess(data: String) { override fun onSuccess(data: String) {
@@ -150,9 +161,11 @@ class BalanceActivity : CKLHBaseActionBarActivity() , View.OnClickListener{
adapter.data = this@BalanceActivity.data adapter.data = this@BalanceActivity.data
adapter.notifyDataSetChanged() adapter.notifyDataSetChanged()
onFinished?.invoke()
} }
override fun onFailed(code: String, msg: String) { override fun onFailed(code: String, msg: String) {
onFinished?.invoke()
toast(msg) toast(msg)
} }
}) })

View File

@@ -1,9 +1,12 @@
package com.ck.ckcollar.app.ui.act.balance package com.ck.ckcollar.app.ui.act.balance
import android.content.pm.ApplicationInfo
import android.os.Bundle import android.os.Bundle
import android.text.TextUtils import android.text.TextUtils
import com.alipay.sdk.app.EnvUtils
import com.alipay.sdk.app.PayTask import com.alipay.sdk.app.PayTask
import com.ck.ckcollar.app.R import com.ck.ckcollar.app.R
import com.ck.ckcollar.app.utils.Const
import com.ck.ckcollar.app.databinding.ActivityRechargeBinding import com.ck.ckcollar.app.databinding.ActivityRechargeBinding
import com.ck.ckcollar.app.model.PayResult import com.ck.ckcollar.app.model.PayResult
import com.ck.ckcollar.app.model.RechargeModel import com.ck.ckcollar.app.model.RechargeModel
@@ -14,7 +17,10 @@ import com.ck.ckcollar.app.utils.networkone.model.TTRequestData
import com.ck.ckcollar.app.utils.networkone.model.TTRequestParam import com.ck.ckcollar.app.utils.networkone.model.TTRequestParam
import com.ck.ckcollar.app.widget.CKEditView import com.ck.ckcollar.app.widget.CKEditView
import com.google.gson.Gson import com.google.gson.Gson
import com.tencent.mm.opensdk.modelpay.PayReq
import com.tencent.mm.opensdk.openapi.WXAPIFactory
import com.tt.kit.model.DataCollection import com.tt.kit.model.DataCollection
import com.tt.kit.utils.LiveDataBus
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -23,7 +29,7 @@ import kotlinx.coroutines.withContext
class RechargeActivity : CKBaseActivity() { class RechargeActivity : CKBaseActivity() {
lateinit var binding: ActivityRechargeBinding lateinit var binding: ActivityRechargeBinding
var payType = "1" var payType = "0"
var model : RechargeModel? = null var model : RechargeModel? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
binding = ActivityRechargeBinding.inflate(layoutInflater) binding = ActivityRechargeBinding.inflate(layoutInflater)
@@ -35,6 +41,17 @@ class RechargeActivity : CKBaseActivity() {
override fun initView() { override fun initView() {
LiveDataBus.get().with(WX_PAY_RESULT, Int::class.java).observe(this) { result ->
when (result) {
0 -> {
toast(getString(R.string.recharge_success))
finish(DataCollection(), 1001)
}
-2 -> toast("已取消微信支付")
else -> toast(getString(R.string.recharge_faild))
}
}
binding.btnAli.setOnClickListener { binding.btnAli.setOnClickListener {
binding.image1.setImageResource(R.mipmap.image_address_check_select) binding.image1.setImageResource(R.mipmap.image_address_check_select)
binding.image2.setImageResource(R.mipmap.image_address_check_narmal) binding.image2.setImageResource(R.mipmap.image_address_check_narmal)
@@ -69,6 +86,8 @@ class RechargeActivity : CKBaseActivity() {
if ("1".equals(payType)){ if ("1".equals(payType)){
aliPay() aliPay()
}else if("0".equals(payType)){
wxPay()
} }
} }
@@ -87,7 +106,10 @@ class RechargeActivity : CKBaseActivity() {
fun aliPay(){ fun aliPay(){
GlobalScope.launch(Dispatchers.IO){ GlobalScope.launch(Dispatchers.IO){
// [支付宝沙箱测试] 仅 Debug 包启用Release 包继续使用正式环境。
if (applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE != 0) {
// EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX)
}
val alipay = PayTask(this@RechargeActivity) val alipay = PayTask(this@RechargeActivity)
val result = alipay.payV2(model?.orderStr, true) val result = alipay.payV2(model?.orderStr, true)
@@ -107,4 +129,54 @@ class RechargeActivity : CKBaseActivity() {
} }
} }
private fun wxPay() {
val payModel = model ?: return
val requiredValues = listOf(
payModel.appId,
payModel.partnerId,
payModel.prepayId,
payModel.packageVal,
payModel.nonceStr,
payModel.timeStamp,
payModel.paySign
)
if (requiredValues.any { it.isNullOrBlank() }) {
hiddenProgeassDialog()
toast("微信支付参数不完整,请检查商户号等支付参数")
return
}
if (payModel.appId != Const.WX_APP_ID) {
hiddenProgeassDialog()
toast("微信支付 AppID 不匹配")
return
}
val api = WXAPIFactory.createWXAPI(this, Const.WX_APP_ID, true)
api.registerApp(Const.WX_APP_ID)
if (!api.isWXAppInstalled) {
hiddenProgeassDialog()
toast("请先安装微信")
return
}
val request = PayReq().apply {
appId = payModel.appId
partnerId = payModel.partnerId
prepayId = payModel.prepayId
packageValue = payModel.packageVal
nonceStr = payModel.nonceStr
timeStamp = payModel.timeStamp
sign = payModel.paySign
extData = payModel.orderNo
}
hiddenProgeassDialog()
if (!api.sendReq(request)) {
toast("微信支付拉起失败")
}
}
companion object {
const val WX_PAY_RESULT = "wx_pay_result"
}
} }

View File

@@ -20,13 +20,19 @@ import com.google.gson.Gson
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
import com.tt.kit.model.Data import com.tt.kit.model.Data
import com.tt.kit.model.DataCollection import com.tt.kit.model.DataCollection
import com.tt.kit.utils.LiveDataBus
import com.tencent.mm.opensdk.modelbiz.WXOpenBusinessView
import com.tencent.mm.opensdk.openapi.WXAPIFactory
import com.ck.ckcollar.app.utils.Const
import java.net.URLEncoder
import java.math.BigDecimal import java.math.BigDecimal
class WithDrawActivity : CKLHBaseActionBarActivity() { class WithDrawActivity : CKLHBaseActionBarActivity() {
lateinit var binding: ActivityWithdrawBinding lateinit var binding: ActivityWithdrawBinding
var model : BalanceModle? = null var model : BalanceModle? = null
private var pendingWithdraw: WithDrawModel? = null
var payType = "1" var payType = "0"
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
binding = ActivityWithdrawBinding.inflate(layoutInflater) binding = ActivityWithdrawBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
@@ -39,6 +45,14 @@ class WithDrawActivity : CKLHBaseActionBarActivity() {
} }
override fun initView() { override fun initView() {
LiveDataBus.get().with(WX_WITHDRAW_RESULT, Int::class.java).observe(this) { resultCode ->
val withdraw = pendingWithdraw ?: return@observe
if (resultCode == 0) {
showWithdrawSuccess(withdraw)
} else {
toast(if (resultCode == -2) "已取消微信收款确认" else "微信提现确认失败")
}
}
binding.btnAli.setOnClickListener { binding.btnAli.setOnClickListener {
binding.image1.setImageResource(R.mipmap.image_address_check_select) binding.image1.setImageResource(R.mipmap.image_address_check_select)
@@ -70,29 +84,34 @@ class WithDrawActivity : CKLHBaseActionBarActivity() {
toast(getString(R.string.no_balance_data)) toast(getString(R.string.no_balance_data))
return return
} }
if (TextUtils.isEmpty(binding.editAmount.text.toString())){ val amountText = binding.editAmount.text.toString()
if (TextUtils.isEmpty(amountText)){
toast(getString(R.string.withdraw_amount_not_empty)) toast(getString(R.string.withdraw_amount_not_empty))
return return
} }
if (binding.editAmount.text.toString().toDouble() > model!!.balance){ val amount = amountText.toBigDecimalOrNull()
if (amount == null || amount < BigDecimal("0.1")) {
toast(getString(R.string.withdraw_amount_minimum))
return
}
if (amount > BigDecimal.valueOf(model!!.balance)){
toast(getString(R.string.withdraw_amount_alert)) toast(getString(R.string.withdraw_amount_alert))
return return
} }
showProgeassDialog(getString(R.string.withdraw)) showProgeassDialog(getString(R.string.withdraw))
TTHttpClient.postJson(this, "提现", TTRequestParam().apply { TTHttpClient.postJson(this, "提现", TTRequestParam().apply {
add(TTRequestData("amount", binding.editAmount.text.toString())) add(TTRequestData("amount", amountText))
add(TTRequestData("payType", payType)) add(TTRequestData("payType", payType))
}, object : ICallback { }, object : ICallback {
override fun onSuccess(data: String) { override fun onSuccess(data: String) {
val withdraw = Gson().fromJson(data, WithDrawModel::class.java)
var model = Gson().fromJson<WithDrawModel>(data, WithDrawModel::class.java) pendingWithdraw = withdraw
toActivity(WithDrawSuccessActivity::class.java, DataCollection().apply { if (withdraw.needConfirm && "0" == payType) {
add(Data("data", Gson().toJson(model))) openWeChatTransferConfirm(withdraw)
} else {
}) showWithdrawSuccess(withdraw)
}
finish()
} }
@@ -104,6 +123,52 @@ class WithDrawActivity : CKLHBaseActionBarActivity() {
} }
private fun openWeChatTransferConfirm(withdraw: WithDrawModel) {
val mchId = withdraw.mchId
val appId = withdraw.appId
val packageInfo = withdraw.authPackageInfo
if (mchId.isNullOrBlank() || appId.isNullOrBlank() || packageInfo.isNullOrBlank()) {
toast("微信收款确认参数不完整")
return
}
if (appId != Const.WX_APP_ID) {
toast("微信支付 AppID 不匹配")
return
}
val api = WXAPIFactory.createWXAPI(this, Const.WX_APP_ID, true)
api.registerApp(Const.WX_APP_ID)
if (!api.isWXAppInstalled) {
toast("请先安装微信")
return
}
if (api.wxAppSupportAPI < 0x28002d33) {
toast("当前微信版本过低,请升级微信")
return
}
val request = WXOpenBusinessView.Req().apply {
businessType = "requestMerchantTransfer"
query = "mchId=${URLEncoder.encode(mchId, "UTF-8")}" +
"&appId=${URLEncoder.encode(appId, "UTF-8")}" +
"&package=${URLEncoder.encode(packageInfo, "UTF-8")}"
}
if (!api.sendReq(request)) {
toast("微信收款确认页拉起失败")
}
}
private fun showWithdrawSuccess(withdraw: WithDrawModel) {
toActivity(WithDrawSuccessActivity::class.java, DataCollection().apply {
add(Data("data", Gson().toJson(withdraw)))
})
finish()
}
companion object {
const val WX_WITHDRAW_RESULT = "wx_withdraw_result"
}
fun getBalanceInfo(){ fun getBalanceInfo(){
TTHttpClient.get(this,"余额", TTRequestParam(),object : ICallback{ TTHttpClient.get(this,"余额", TTRequestParam(),object : ICallback{

View File

@@ -0,0 +1,69 @@
package com.ck.ckcollar.app.ui.act.customer
import android.content.Context
import android.graphics.drawable.Drawable
import android.widget.ImageView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
import com.ck.ckcollar.app.R
object ChatImageLoader {
fun load(context: Context, imageView: ImageView, imageUrl: String) {
imageView.tag = imageUrl
resetSize(imageView)
Glide.with(context)
.load(imageUrl)
.placeholder(R.mipmap.image_default)
.listener(object : RequestListener<Drawable> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable>?,
isFirstResource: Boolean
): Boolean = false
override fun onResourceReady(
resource: Drawable,
model: Any,
target: Target<Drawable>?,
dataSource: DataSource,
isFirstResource: Boolean
): Boolean {
if (imageView.tag == imageUrl) {
setSize(imageView, resource.intrinsicWidth, resource.intrinsicHeight)
}
return false
}
})
.into(imageView)
}
private fun resetSize(imageView: ImageView) {
val density = imageView.resources.displayMetrics.density
imageView.layoutParams = imageView.layoutParams.apply {
width = maxWidth(imageView, density)
height = (200 * density).toInt()
}
}
private fun setSize(imageView: ImageView, sourceWidth: Int, sourceHeight: Int) {
if (sourceWidth <= 0 || sourceHeight <= 0) return
val density = imageView.resources.displayMetrics.density
val maxWidth = maxWidth(imageView, density).toFloat()
val maxHeight = 200 * density
val scale = minOf(1f, maxWidth / sourceWidth, maxHeight / sourceHeight)
imageView.layoutParams = imageView.layoutParams.apply {
width = (sourceWidth * scale).toInt().coerceAtLeast(1)
height = (sourceHeight * scale).toInt().coerceAtLeast(1)
}
}
private fun maxWidth(imageView: ImageView, density: Float): Int {
val requestedWidth = (200 * density).toInt()
val availableWidth = imageView.resources.displayMetrics.widthPixels - (155 * density).toInt()
return minOf(requestedWidth, availableWidth.coerceAtLeast(1))
}
}

View File

@@ -1,7 +1,9 @@
package com.ck.ckcollar.app.ui.act.customer package com.ck.ckcollar.app.ui.act.customer
import android.Manifest
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.drawable.Drawable
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
@@ -10,21 +12,23 @@ import android.os.Handler
import android.os.Looper import android.os.Looper
import android.provider.MediaStore import android.provider.MediaStore
import android.text.Editable import android.text.Editable
import android.text.Spannable
import android.text.SpannableString
import android.text.TextUtils import android.text.TextUtils
import android.text.TextWatcher import android.text.TextWatcher
import android.text.style.ImageSpan
import android.view.KeyEvent import android.view.KeyEvent
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.TextView import android.widget.TextView
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
import com.ck.ckcollar.app.CKApp import com.ck.ckcollar.app.CKApp
import com.ck.ckcollar.app.R import com.ck.ckcollar.app.R
import com.ck.ckcollar.app.action.ActionCode import com.ck.ckcollar.app.action.ActionCode
@@ -40,6 +44,7 @@ import com.ck.ckcollar.app.ui.base.CKBaseActivity
import com.ck.ckcollar.app.ui.dialog.CKAlertDialog import com.ck.ckcollar.app.ui.dialog.CKAlertDialog
import com.ck.ckcollar.app.utils.CKUtils import com.ck.ckcollar.app.utils.CKUtils
import com.ck.ckcollar.app.utils.Const import com.ck.ckcollar.app.utils.Const
import com.ck.ckcollar.app.utils.LubanCompressUtil
import com.ck.ckcollar.app.utils.networkone.ICallback import com.ck.ckcollar.app.utils.networkone.ICallback
import com.ck.ckcollar.app.utils.networkone.TTHttpClient import com.ck.ckcollar.app.utils.networkone.TTHttpClient
import com.ck.ckcollar.app.utils.networkone.model.TTRequestData import com.ck.ckcollar.app.utils.networkone.model.TTRequestData
@@ -53,9 +58,49 @@ import com.tt.kit.model.DataCollection
import com.tt.kit.utils.KeyboardUtils import com.tt.kit.utils.KeyboardUtils
import com.tt.kit.utils.TTLog import com.tt.kit.utils.TTLog
import com.tt.kit.utils.TTUtils import com.tt.kit.utils.TTUtils
import io.noties.markwon.Markwon
import java.io.File import java.io.File
import java.util.UUID import java.util.UUID
import kotlin.math.min
private object CustomerMarkdownDetector {
private val blockMarkdown = Regex(
"(?m)^(?:\\s{0,3}(?:#{1,6}\\s+|[-*+]\\s+|>\\s+|\\d+\\.\\s+|```|~~~|(?:-{3,}|_{3,}|\\*{3,})\\s*$))"
)
private val inlineMarkdown = Regex("(?:\\*\\*[^\\n]+?\\*\\*|`[^\\n]+?`|\\[[^\\]]+?\\]\\([^\\s)]+?\\))")
fun isMarkdown(content: String): Boolean = content.isNotBlank() &&
(blockMarkdown.containsMatchIn(content) || inlineMarkdown.containsMatchIn(content))
fun normalize(content: String): String {
val normalized = content
// SSE chunks contain JSON-escaped line breaks; Markwon otherwise renders
// "\\n\\n" as "nn" and keeps the first list item inside the heading.
.replace("\\r\\n", "\n")
.replace("\\n", "\n")
// AI responses commonly omit the required spaces after block markers.
.replace(Regex("(?m)^(\\s{0,3}#{1,6})(?=\\S)"), "$1 ")
.replace(Regex("(?m)^(\\s{0,3}>)(?=\\S)"), "$1 ")
.replace(Regex("(?m)^(\\s{0,3}[-+])(?!\\s)(?=\\S)"), "$1 ")
.replace(Regex("(?m)^(\\s{0,3}\\*)(?![\\s*])(?=\\S)"), "$1 ")
.replace(Regex("(?m)^(\\s{0,3}\\d+\\.)(?=\\S)"), "$1 ")
// Split compact numbered sections such as "。2.**标题**" into list rows.
.replace(Regex("(\\d+)\\.\\s*(?=\\*\\*)"), "$1. ")
.replace(Regex("([^\\n])(?=\\d+\\. \\*\\*)")) { match ->
match.value + "\n"
}
.replace(Regex("([^\\n])(?=免责声明[:])")) { match ->
match.value + "\n\n"
}
// TextView has no CSS-like heading margins, so preserve a blank line
// after Markdown headings for readable streamed responses.
return normalized.replace(
Regex("(?m)^(\\s{0,3}#{1,6}\\s+[^\\n]+)\\n(?!\\n)")
) { match ->
match.groupValues[1] + "\n\n"
}
}
}
class CustomerActivity : CKBaseActivity() { class CustomerActivity : CKBaseActivity() {
@@ -64,6 +109,8 @@ class CustomerActivity : CKBaseActivity() {
var data = mutableListOf<CustomerMessageModel.MessageItemModel>() var data = mutableListOf<CustomerMessageModel.MessageItemModel>()
var path = "" var path = ""
private var isSending = false
private var isAiResponding = false
var url = "" var url = ""
var lock = true var lock = true
@@ -71,7 +118,6 @@ class CustomerActivity : CKBaseActivity() {
binding = ActivityCustomerBinding.inflate(layoutInflater) binding = ActivityCustomerBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
checkAppPermissions()
setTitleText(getString(R.string.customer_service4)) setTitleText(getString(R.string.customer_service4))
@@ -94,6 +140,28 @@ class CustomerActivity : CKBaseActivity() {
binding.recyclerView.adapter = customerMessageAdapter binding.recyclerView.adapter = customerMessageAdapter
binding.editMessage.setHorizontallyScrolling(false); binding.editMessage.setHorizontallyScrolling(false);
binding.btnSend.setOnClickListener {
if (isAiResponding) {
toast("请等待当前问题回答结束")
return@setOnClickListener
}
isSending = true
// Reset the action controls immediately. The send flow captures the
// submitted text and image path before clearing the visible draft.
binding.btnSend.visibility = View.GONE
binding.btnMore.visibility = View.VISIBLE
binding.editMessage.onEditorAction(EditorInfo.IME_ACTION_SEND)
}
updateSendControls()
// Use the traditional multiline keyboard action; sending is handled by the
// activity's own message flow rather than the IME action button.
binding.editMessage.setSingleLine(false)
binding.editMessage.imeOptions = EditorInfo.IME_ACTION_NONE
binding.editMessage.setRawInputType(android.text.InputType.TYPE_CLASS_TEXT or android.text.InputType.TYPE_TEXT_FLAG_MULTI_LINE)
// setSingleLine(false) resets the XML maxLines value, so apply it last.
binding.editMessage.maxLines = 4
binding.editMessage.maxHeight = (70 * resources.displayMetrics.density).toInt()
binding.editMessage.isVerticalScrollBarEnabled = true
binding.editMessage.setOnEditorActionListener(object : TextView.OnEditorActionListener { binding.editMessage.setOnEditorActionListener(object : TextView.OnEditorActionListener {
override fun onEditorAction( override fun onEditorAction(
@@ -101,21 +169,21 @@ class CustomerActivity : CKBaseActivity() {
actionId: Int, actionId: Int,
ketEvent: KeyEvent? ketEvent: KeyEvent?
): Boolean { ): Boolean {
if (actionId == EditorInfo.IME_ACTION_UNSPECIFIED || if (actionId == EditorInfo.IME_ACTION_SEND) {
actionId == EditorInfo.IME_ACTION_SEND ||
(ketEvent != null && ketEvent.keyCode == KeyEvent.KEYCODE_ENTER)
) {
if (lock) { if (lock) {
var text = binding.editMessage.text.toString() // Whitespace-only input is not a message. A selected image may still be sent alone.
var index = text.indexOf("$$$$$") >= 0 val text = binding.editMessage.text.toString().trim()
if (!index) { if (text.isNotEmpty() || path.isNotEmpty()) {
path = ""
}
text = text.replace("$$$$$", "")
if (!TextUtils.isEmpty(text) || !TextUtils.isEmpty(path)) {
lock = false lock = false
KeyboardUtils.hideKeyboard(this@CustomerActivity)
binding.editMessage.clearFocus()
handler.post { handler.post {
sendMessage(UUID.randomUUID().toString(),text,false) if (!TextUtils.isEmpty(path)) {
uploadImage(text, path)
} else {
sendMessage(UUID.randomUUID().toString(), text, false, "")
}
clearInputViews()
} }
} }
} }
@@ -153,31 +221,19 @@ class CustomerActivity : CKBaseActivity() {
p2: Int, p2: Int,
p3: Int p3: Int
) { ) {
try { if (p0?.toString()?.trim()?.isNotEmpty() == true) isSending = false
var text = binding.editMessage.text.toString() updateSendControls()
var index = text.indexOf("$$$$$") >= 0
// if (!index) {
// path = ""
// }
val lineCount: Int? = binding.editMessage.getLineCount()
val lineHeight: Int = binding.editMessage.getLineHeight()
val maxHeight: Int = lineCount!! * lineHeight
binding.editMessage.setHeight(min(maxHeight, maxHeight))
}catch (e : Exception){
e.toString()
}
} }
}) })
binding.btnMore.setOnClickListener { binding.btnMore.setOnClickListener {
if (binding.contentBottom.visibility == View.GONE) { if (binding.contentBottom.visibility == View.GONE) {
KeyboardUtils.hideKeyboard(this@CustomerActivity) val inputMethodManager =
getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.hideSoftInputFromWindow(binding.editMessage.windowToken, 0)
binding.editMessage.clearFocus()
binding.contentBottom.visibility = View.VISIBLE binding.contentBottom.visibility = View.VISIBLE
} else { } else {
binding.contentBottom.visibility = View.GONE binding.contentBottom.visibility = View.GONE
binding.editMessage.requestFocus()
KeyboardUtils.showKeyboard(binding.editMessage)
} }
} }
binding.btnSmile.setOnClickListener { binding.btnSmile.setOnClickListener {
@@ -185,25 +241,35 @@ class CustomerActivity : CKBaseActivity() {
binding.editMessage.requestFocus() binding.editMessage.requestFocus()
KeyboardUtils.showKeyboard(binding.editMessage) KeyboardUtils.showKeyboard(binding.editMessage)
} }
binding.btnDeleteImage.setOnClickListener {
clearSelectedImage()
}
//拍照
binding.conetnt1.setOnClickListener { binding.conetnt1.setOnClickListener {
if (TextUtils.isEmpty(path)) { if (TextUtils.isEmpty(path)) {
takePhoto() getPermissionRequst(
Manifest.permission.CAMERA,
REQUEST_CAMERA_PERMISSION
)
} else { } else {
toast(getString(R.string.only_one_photo)) toast(getString(R.string.only_one_photo))
} }
} }
//相册
binding.conetnt2.setOnClickListener { binding.conetnt2.setOnClickListener {
if (TextUtils.isEmpty(path)) { if (TextUtils.isEmpty(path)) {
//相册 val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
val i = Intent( Manifest.permission.READ_MEDIA_IMAGES
Intent.ACTION_PICK, } else {
MediaStore.Images.Media.EXTERNAL_CONTENT_URI Manifest.permission.READ_EXTERNAL_STORAGE
}
getPermissionRequst(
permission,
REQUEST_PHOTO_PERMISSION
) )
i.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,"image/*");
startActivityForResult(i, 56)
} else { } else {
toast(getString(R.string.only_one_photo)) toast(getString(R.string.only_one_photo))
} }
@@ -223,7 +289,22 @@ class CustomerActivity : CKBaseActivity() {
} }
} }
handleMessage() handleMessage()
binding.btnSmile.visibility = View.GONE;
}
override fun onPermissionsGranted(requestCode: Int, permissions: Array<String>) {
when (requestCode) {
REQUEST_CAMERA_PERMISSION -> takePhoto()
REQUEST_PHOTO_PERMISSION -> {
val intent = Intent(
Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
).apply {
setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*")
}
startActivityForResult(intent, 56)
}
}
} }
override fun initData() { override fun initData() {
@@ -270,7 +351,7 @@ class CustomerActivity : CKBaseActivity() {
if (!TextUtils.isEmpty(sendConetnt) || !TextUtils.isEmpty(url)){ if (!TextUtils.isEmpty(sendConetnt) || !TextUtils.isEmpty(url)){
handler.post { handler.post {
sendMessage2(UUID.randomUUID().toString(),sendConetnt,true) sendMessage2(UUID.randomUUID().toString(),sendConetnt,true, url)
} }
} }
} }
@@ -297,15 +378,18 @@ class CustomerActivity : CKBaseActivity() {
}).show() }).show()
} }
fun sendMessage(uuid :String ,content: String,isResend : Boolean) { fun sendMessage(uuid :String ,content: String,isResend : Boolean, imageUrl: String) {
if (!TextUtils.isEmpty(url)) { isAiResponding = true
val rawStreamResponse = StringBuilder()
if (!TextUtils.isEmpty(imageUrl)) {
this@CustomerActivity.data.add(CustomerMessageModel.MessageItemModel().apply { this@CustomerActivity.data.add(CustomerMessageModel.MessageItemModel().apply {
senderId = CKApp.app.userInfo?.id!! senderId = CKApp.app.userInfo?.id!!
this.content = content this.content = content
this.senderAvatar = CKApp.app.userInfo?.avatar this.senderAvatar = CKApp.app.userInfo?.avatar
this.senderName = CKApp.app.userInfo?.custName ?: "" this.senderName = CKApp.app.userInfo?.custName ?: ""
this.url = this@CustomerActivity.url this.url = imageUrl
}) })
} }
if (!TextUtils.isEmpty(content) && !isResend) { if (!TextUtils.isEmpty(content) && !isResend) {
@@ -325,13 +409,13 @@ class CustomerActivity : CKBaseActivity() {
TTHttpClient.postJsonStream3(this, "发送会话消息stream", TTRequestParam().apply { TTHttpClient.postJsonStream3(this, "发送会话消息stream", TTRequestParam().apply {
add(TTRequestData("imageUrl", url)) add(TTRequestData("imageUrl", imageUrl))
add(TTRequestData("question", content)) add(TTRequestData("question", content))
}, object : ICallback { }, object : ICallback {
override fun onSuccess(data: String) { override fun onSuccess(data: String) {
lock = true rawStreamResponse.append(data)
// var model = Gson().fromJson<AIMessageModel>(data, AIMessageModel::class.java) // var model = Gson().fromJson<AIMessageModel>(data, AIMessageModel::class.java)
@@ -354,9 +438,6 @@ class CustomerActivity : CKBaseActivity() {
} }
binding.editMessage.setText("")
path = ""
url = ""
customerMessageAdapter.data = this@CustomerActivity.data customerMessageAdapter.data = this@CustomerActivity.data
customerMessageAdapter.notifyDataSetChanged() customerMessageAdapter.notifyDataSetChanged()
@@ -376,13 +457,19 @@ class CustomerActivity : CKBaseActivity() {
} }
override fun onFailed(code: String, msg: String) { override fun onFailed(code: String, msg: String) {
isAiResponding = false
lock = true lock = true
TTLog.e("AI_STREAM_FULL[$uuid][FAILED]: $rawStreamResponse")
// toast(msg) // toast(msg)
//TTLog.e(msg) //TTLog.e(msg)
} }
})
binding.editMessage.setText("") override fun onComplete() {
isAiResponding = false
lock = true
TTLog.e("AI_STREAM_FULL[$uuid]: $rawStreamResponse")
}
})
customerMessageAdapter.data = this@CustomerActivity.data customerMessageAdapter.data = this@CustomerActivity.data
customerMessageAdapter.notifyDataSetChanged() customerMessageAdapter.notifyDataSetChanged()
@@ -393,7 +480,9 @@ class CustomerActivity : CKBaseActivity() {
fun sendMessage2(uuid :String ,content: String,isResend : Boolean) { fun sendMessage2(uuid :String ,content: String,isResend : Boolean, imageUrl: String) {
isAiResponding = true
val rawStreamResponse = StringBuilder()
lock = false lock = false
if (!TextUtils.isEmpty(content) && !isResend) { if (!TextUtils.isEmpty(content) && !isResend) {
this@CustomerActivity.data.add(CustomerMessageModel.MessageItemModel().apply { this@CustomerActivity.data.add(CustomerMessageModel.MessageItemModel().apply {
@@ -412,13 +501,13 @@ class CustomerActivity : CKBaseActivity() {
TTHttpClient.postJsonStream3(this, "发送会话消息stream", TTRequestParam().apply { TTHttpClient.postJsonStream3(this, "发送会话消息stream", TTRequestParam().apply {
add(TTRequestData("imageUrl", url)) add(TTRequestData("imageUrl", imageUrl))
add(TTRequestData("question", content)) add(TTRequestData("question", content))
}, object : ICallback { }, object : ICallback {
override fun onSuccess(data: String) { override fun onSuccess(data: String) {
lock = true rawStreamResponse.append(data)
// var model = Gson().fromJson<AIMessageModel>(data, AIMessageModel::class.java) // var model = Gson().fromJson<AIMessageModel>(data, AIMessageModel::class.java)
@@ -441,9 +530,6 @@ class CustomerActivity : CKBaseActivity() {
} }
binding.editMessage.setText("")
path = ""
url = ""
customerMessageAdapter.data = this@CustomerActivity.data customerMessageAdapter.data = this@CustomerActivity.data
customerMessageAdapter.notifyDataSetChanged() customerMessageAdapter.notifyDataSetChanged()
@@ -463,13 +549,19 @@ class CustomerActivity : CKBaseActivity() {
} }
override fun onFailed(code: String, msg: String) { override fun onFailed(code: String, msg: String) {
isAiResponding = false
lock = true lock = true
TTLog.e("AI_STREAM_FULL[$uuid][FAILED]: $rawStreamResponse")
// toast(msg) // toast(msg)
//TTLog.e(msg) //TTLog.e(msg)
} }
})
binding.editMessage.setText("") override fun onComplete() {
isAiResponding = false
lock = true
TTLog.e("AI_STREAM_FULL[$uuid]: $rawStreamResponse")
}
})
customerMessageAdapter.data = this@CustomerActivity.data customerMessageAdapter.data = this@CustomerActivity.data
customerMessageAdapter.notifyDataSetChanged() customerMessageAdapter.notifyDataSetChanged()
@@ -479,10 +571,10 @@ class CustomerActivity : CKBaseActivity() {
} }
fun uploadImage() { fun uploadImage(content: String, imagePath: String) {
var param = TTRequestParam() var param = TTRequestParam()
param.files.add(File(path)) param.files.add(File(imagePath))
showProgeassDialog() showProgeassDialog()
TTHttpClient.postFile(this, "上传照片s", param, object : ICallback { TTHttpClient.postFile(this, "上传照片s", param, object : ICallback {
@@ -490,33 +582,25 @@ class CustomerActivity : CKBaseActivity() {
hiddenProgeassDialog() hiddenProgeassDialog()
var model = Gson().fromJson<UploadModel>(data, UploadModel::class.java) var model = Gson().fromJson<UploadModel>(data, UploadModel::class.java)
url = model.urls handler.post {
sendMessage(UUID.randomUUID().toString(), content, false, model.urls)
}
} }
override fun onFailed(code: String, msg: String) { override fun onFailed(code: String, msg: String) {
hiddenProgeassDialog() hiddenProgeassDialog()
lock = true
if (path.isEmpty() && binding.editMessage.text.toString().isEmpty()) {
path = imagePath
showImagePreview(imagePath)
binding.editMessage.setText(content)
}
toast(msg) toast(msg)
} }
}) })
} }
fun addImage(path: String) {
try {
var bitmap = TTUtils.getBitmap(path, 300, 300)
var imageSpan = ImageSpan(bitmap!!);
var spannableString = SpannableString("$$$$$");
spannableString.setSpan(
imageSpan, 0, 5,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
);
binding.editMessage.text?.insert(0, spannableString);
} catch (e: Exception) {
e.printStackTrace();
}
}
fun getList() { fun getList() {
TTHttpClient.get(this, "会话消息列表", TTRequestParam(), object : ICallback { TTHttpClient.get(this, "会话消息列表", TTRequestParam(), object : ICallback {
override fun onSuccess(data: String) { override fun onSuccess(data: String) {
@@ -546,17 +630,89 @@ class CustomerActivity : CKBaseActivity() {
if (requestCode == 55 && resultCode == RESULT_OK) { if (requestCode == 55 && resultCode == RESULT_OK) {
path = PreferencesUtils.getString(this@CustomerActivity, Const.IMAGE_PATH, "")!! path = PreferencesUtils.getString(this@CustomerActivity, Const.IMAGE_PATH, "")!!
prepareSelectedImage()
addImage(path!!)
uploadImage()
} else if (requestCode == 56 && resultCode == RESULT_OK) { } else if (requestCode == 56 && resultCode == RESULT_OK) {
path = TTUtils.getImageUrl(this, data!!.getData()); path = TTUtils.getImageUrl(this, data!!.getData());
addImage(path) prepareSelectedImage()
uploadImage()
} }
} }
private fun prepareSelectedImage() {
if (TextUtils.isEmpty(path)) return
LubanCompressUtil.getCompressFile(
this,
File(path),
object : LubanCompressUtil.CompressCallback {
override fun success(file: File) {
if (isFinishing || isDestroyed) return
path = file.absolutePath
lock = true
binding.contentBottom.visibility = View.GONE
showImagePreview(path)
binding.editMessage.requestFocus()
KeyboardUtils.showKeyboard(binding.editMessage)
// Rebind the IME after selecting an image so its action button is
// available even though the text field itself is empty.
binding.editMessage.postDelayed({
val imm = getSystemService(INPUT_METHOD_SERVICE) as? android.view.inputmethod.InputMethodManager
imm?.restartInput(binding.editMessage)
}, 150L)
}
override fun fail(failMsg: String) {
if (isFinishing || isDestroyed) return
lock = true
path = ""
toast(failMsg)
}
}
)
}
private fun showImagePreview(imagePath: String) {
isSending = false
binding.contentImagePreview.visibility = View.VISIBLE
updateSendControls()
binding.imagePreview.scaleType = android.widget.ImageView.ScaleType.CENTER_CROP
Glide.with(this)
.load(imagePath)
.into(binding.imagePreview)
}
private fun clearSelectedImage() {
path = ""
url = ""
binding.imagePreview.setImageDrawable(null)
binding.contentImagePreview.visibility = View.GONE
updateSendControls()
}
private fun clearInputViews() {
binding.editMessage.setText("")
path = ""
url = ""
binding.imagePreview.setImageDrawable(null)
binding.contentImagePreview.visibility = View.GONE
// Sending has already been initiated; keep the controls in their idle state
// until the user starts composing the next draft.
binding.btnSend.visibility = View.GONE
binding.btnMore.visibility = View.VISIBLE
}
private fun updateSendControls() {
val hasImage = path.isNotEmpty()
val hasText = binding.editMessage.text.toString().trim().isNotEmpty()
if (isSending) {
binding.btnSend.visibility = View.GONE
binding.btnMore.visibility = View.VISIBLE
return
}
binding.btnSend.visibility = if (hasImage || hasText) View.VISIBLE else View.GONE
binding.btnMore.visibility = if (hasImage) View.GONE else View.VISIBLE
}
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
@@ -602,6 +758,8 @@ class CustomerActivity : CKBaseActivity() {
var data: List<CustomerMessageModel.MessageItemModel>, var data: List<CustomerMessageModel.MessageItemModel>,
var onItemClickListenner: OnItemClickListenner var onItemClickListenner: OnItemClickListenner
) : RecyclerView.Adapter<CustomerMessageAdapter.CustomerMessageHolder>() { ) : RecyclerView.Adapter<CustomerMessageAdapter.CustomerMessageHolder>() {
private val markwon = Markwon.create(context)
override fun onCreateViewHolder( override fun onCreateViewHolder(
parent: ViewGroup, parent: ViewGroup,
viewType: Int viewType: Int
@@ -626,7 +784,16 @@ class CustomerActivity : CKBaseActivity() {
holder.binding.contentTo.visibility = View.GONE holder.binding.contentTo.visibility = View.GONE
holder.binding.contentFrom.visibility = View.VISIBLE holder.binding.contentFrom.visibility = View.VISIBLE
holder.binding.textFrom.text = model.content val content = model.content.orEmpty()
val normalizedContent = CustomerMarkdownDetector.normalize(content)
if (CustomerMarkdownDetector.isMarkdown(normalizedContent)) {
markwon.setMarkdown(
holder.binding.textFrom,
normalizedContent
)
} else {
holder.binding.textFrom.text = content
}
holder.binding.textFromNick.text = model.senderName holder.binding.textFromNick.text = model.senderName
Glide.with(context) Glide.with(context)
@@ -658,14 +825,42 @@ class CustomerActivity : CKBaseActivity() {
if (!TextUtils.isEmpty(model.url)) { if (!TextUtils.isEmpty(model.url)) {
holder.binding.textTo.visibility = View.GONE holder.binding.textTo.visibility = View.GONE
holder.binding.imageContentTo.visibility = View.VISIBLE holder.binding.imageContentTo.visibility = View.VISIBLE
val imageView = holder.binding.imageContentTo
val imageUrl = model.url!!
imageView.setTag(imageUrl)
resetImageContentSize(imageView)
Glide.with(context) Glide.with(context)
.load( model.url) .load(imageUrl)
.placeholder(R.mipmap.image_default) .placeholder(R.mipmap.image_default)
.into(holder.binding.imageContentTo) .listener(object : RequestListener<Drawable> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable>?,
isFirstResource: Boolean
): Boolean = false
holder.binding.imageContentTo.setTag(model.url) override fun onResourceReady(
holder.binding.imageContentTo.setOnClickListener(imageClick) resource: Drawable,
model: Any,
target: Target<Drawable>?,
dataSource: DataSource,
isFirstResource: Boolean
): Boolean {
if (imageView.tag == imageUrl) {
setImageContentSize(
imageView,
resource.intrinsicWidth,
resource.intrinsicHeight
)
}
return false
}
})
.into(imageView)
imageView.setOnClickListener(imageClick)
} else { } else {
holder.binding.textTo.visibility = View.VISIBLE holder.binding.textTo.visibility = View.VISIBLE
holder.binding.imageContentTo.visibility = View.GONE holder.binding.imageContentTo.visibility = View.GONE
@@ -680,6 +875,39 @@ class CustomerActivity : CKBaseActivity() {
} }
} }
private fun resetImageContentSize(imageView: View) {
val density = imageView.resources.displayMetrics.density
imageView.layoutParams = imageView.layoutParams.apply {
width = getMaxImageWidth(density)
height = (200 * density).toInt()
}
}
private fun setImageContentSize(imageView: View, sourceWidth: Int, sourceHeight: Int) {
if (sourceWidth <= 0 || sourceHeight <= 0) return
val density = imageView.resources.displayMetrics.density
val maxWidth = getMaxImageWidth(density).toFloat()
val maxHeight = (200 * density).toFloat()
val scale = minOf(
1f,
maxWidth / sourceWidth.toFloat(),
maxHeight / sourceHeight.toFloat()
)
imageView.layoutParams = imageView.layoutParams.apply {
width = (sourceWidth * scale).toInt().coerceAtLeast(1)
height = (sourceHeight * scale).toInt().coerceAtLeast(1)
}
}
private fun getMaxImageWidth(density: Float): Int {
val requestedWidth = (200 * density).toInt()
// Reserve the avatar, paddings, and the bubble's left inset.
val availableWidth = context.resources.displayMetrics.widthPixels - (155 * density).toInt()
return minOf(requestedWidth, availableWidth.coerceAtLeast(1))
}
override fun getItemCount(): Int { override fun getItemCount(): Int {
return data.size return data.size
} }
@@ -715,4 +943,9 @@ class CustomerActivity : CKBaseActivity() {
} }
} }
companion object {
private const val REQUEST_CAMERA_PERMISSION = 1001
private const val REQUEST_PHOTO_PERMISSION = 1002
}
} }

View File

@@ -0,0 +1,891 @@
package com.ck.ckcollar.app.ui.act.customer
import android.Manifest
import android.content.Context
import android.content.Intent
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.os.Handler
import android.os.Looper
import android.provider.MediaStore
import android.text.Editable
import android.text.InputType
import android.text.TextUtils
import android.text.TextWatcher
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.ImageView
import android.widget.TextView
import androidx.core.content.FileProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
import com.ck.ckcollar.app.CKApp
import com.ck.ckcollar.app.R
import com.ck.ckcollar.app.action.ActionCode
import com.ck.ckcollar.app.databinding.ActivityCustomerBinding
import com.ck.ckcollar.app.databinding.LayoutItemAiCustomerMessageBinding
import com.ck.ckcollar.app.databinding.LayoutItemCustomerMessageBinding
import com.ck.ckcollar.app.listenner.OnItemClickListenner
import com.ck.ckcollar.app.model.AIMessageModel
import com.ck.ckcollar.app.model.CustomerMessageModel
import com.ck.ckcollar.app.model.UploadModel
import com.ck.ckcollar.app.ui.act.petmanager.ImageViewActivity
import com.ck.ckcollar.app.ui.base.CKBaseActivity
import com.ck.ckcollar.app.ui.dialog.CKAlertDialog
import com.ck.ckcollar.app.utils.CKUtils
import com.ck.ckcollar.app.utils.Const
import com.ck.ckcollar.app.utils.LubanCompressUtil
import com.ck.ckcollar.app.utils.networkone.ICallback
import com.ck.ckcollar.app.utils.networkone.TTHttpClient
import com.ck.ckcollar.app.utils.networkone.model.TTRequestData
import com.ck.ckcollar.app.utils.networkone.model.TTRequestParam
import com.cyclone.shadowsocks.utils.PreferencesUtils
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.tt.kit.base.TTBaseActivity
import com.tt.kit.model.Data
import com.tt.kit.model.DataCollection
import com.tt.kit.utils.KeyboardUtils
import com.tt.kit.utils.TTLog
import com.tt.kit.utils.TTUtils
import java.io.File
import java.util.UUID
class CustomerActivity_copy : CKBaseActivity() {
lateinit var binding: ActivityCustomerBinding
lateinit var customerMessageAdapter: CustomerMessageAdapter
var data = mutableListOf<CustomerMessageModel.MessageItemModel>()
var path = ""
private var isSending = false
private var isAiResponding = false
var url = ""
var lock = true
override fun onCreate(savedInstanceState: Bundle?) {
binding = ActivityCustomerBinding.inflate(layoutInflater)
setContentView(binding.root)
super.onCreate(savedInstanceState)
setTitleText(getString(R.string.customer_service4))
setRightText(getString(R.string.clear))
}
override fun initView() {
binding.recyclerView.layoutManager =
LinearLayoutManager(this@CustomerActivity_copy, RecyclerView.VERTICAL, false)
binding.recyclerView.setHasFixedSize(true)
customerMessageAdapter =
CustomerMessageAdapter(this@CustomerActivity_copy, data, object : OnItemClickListenner {
override fun onClick(
pos: Int,
model: Any
) {
}
})
binding.recyclerView.adapter = customerMessageAdapter
binding.editMessage.setHorizontallyScrolling(false);
binding.btnSend.setOnClickListener {
if (isAiResponding) {
toast("请等待当前问题回答结束")
return@setOnClickListener
}
isSending = true
// Reset the action controls immediately. The send flow captures the
// submitted text and image path before clearing the visible draft.
binding.btnSend.visibility = View.GONE
binding.btnMore.visibility = View.VISIBLE
binding.editMessage.onEditorAction(EditorInfo.IME_ACTION_SEND)
}
updateSendControls()
// Use the traditional multiline keyboard action; sending is handled by the
// activity's own message flow rather than the IME action button.
binding.editMessage.setSingleLine(false)
binding.editMessage.imeOptions = EditorInfo.IME_ACTION_NONE
binding.editMessage.setRawInputType(InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_MULTI_LINE)
// setSingleLine(false) resets the XML maxLines value, so apply it last.
binding.editMessage.maxLines = 4
binding.editMessage.maxHeight = (70 * resources.displayMetrics.density).toInt()
binding.editMessage.isVerticalScrollBarEnabled = true
binding.editMessage.setOnEditorActionListener(object : TextView.OnEditorActionListener {
override fun onEditorAction(
p0: TextView?,
actionId: Int,
ketEvent: KeyEvent?
): Boolean {
if (actionId == EditorInfo.IME_ACTION_SEND) {
if (lock) {
// Whitespace-only input is not a message. A selected image may still be sent alone.
val text = binding.editMessage.text.toString().trim()
if (text.isNotEmpty() || path.isNotEmpty()) {
lock = false
KeyboardUtils.hideKeyboard(this@CustomerActivity_copy)
binding.editMessage.clearFocus()
handler.post {
if (!TextUtils.isEmpty(path)) {
uploadImage(text, path)
} else {
sendMessage(UUID.randomUUID().toString(), text, false, "")
}
clearInputViews()
}
}
}
}
return false
}
})
binding.editMessage.setOnClickListener {
binding.contentBottom.visibility = View.GONE
}
binding.editMessage.onFocusChangeListener = object : View.OnFocusChangeListener{
override fun onFocusChange(p0: View?, p1: Boolean) {
if (p1){
binding.contentBottom.visibility = View.GONE
}
}
}
binding.editMessage.addTextChangedListener(object : TextWatcher{
override fun afterTextChanged(p0: Editable?) {
}
override fun beforeTextChanged(
p0: CharSequence?,
p1: Int,
p2: Int,
p3: Int
) {
}
override fun onTextChanged(
p0: CharSequence?,
p1: Int,
p2: Int,
p3: Int
) {
if (p0?.toString()?.trim()?.isNotEmpty() == true) isSending = false
updateSendControls()
}
})
binding.btnMore.setOnClickListener {
if (binding.contentBottom.visibility == View.GONE) {
val inputMethodManager =
getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.hideSoftInputFromWindow(binding.editMessage.windowToken, 0)
binding.editMessage.clearFocus()
binding.contentBottom.visibility = View.VISIBLE
} else {
binding.contentBottom.visibility = View.GONE
}
}
binding.btnSmile.setOnClickListener {
binding.contentBottom.visibility = View.GONE
binding.editMessage.requestFocus()
KeyboardUtils.showKeyboard(binding.editMessage)
}
binding.btnDeleteImage.setOnClickListener {
clearSelectedImage()
}
//拍照
binding.conetnt1.setOnClickListener {
if (TextUtils.isEmpty(path)) {
getPermissionRequst(
Manifest.permission.CAMERA,
REQUEST_CAMERA_PERMISSION
)
} else {
toast(getString(R.string.only_one_photo))
}
}
//相册
binding.conetnt2.setOnClickListener {
if (TextUtils.isEmpty(path)) {
val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
Manifest.permission.READ_MEDIA_IMAGES
} else {
Manifest.permission.READ_EXTERNAL_STORAGE
}
getPermissionRequst(
permission,
REQUEST_PHOTO_PERMISSION
)
} else {
toast(getString(R.string.only_one_photo))
}
}
Handler(Looper.getMainLooper()).post {
binding.recyclerView.scrollToPosition(this@CustomerActivity_copy.data.size - 1)
binding.recyclerView.post {
if (customerMessageAdapter.itemCount > 0) {
val lastView = binding.recyclerView.layoutManager?.findViewByPosition(customerMessageAdapter.itemCount - 1)
lastView?.let {
val bottomOffset = it.bottom - binding.recyclerView.height
binding.recyclerView.scrollBy(0, bottomOffset)
}
}
}
}
handleMessage()
binding.btnSmile.visibility = View.GONE;
}
override fun onPermissionsGranted(requestCode: Int, permissions: Array<String>) {
when (requestCode) {
REQUEST_CAMERA_PERMISSION -> takePhoto()
REQUEST_PHOTO_PERMISSION -> {
val intent = Intent(
Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
).apply {
setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*")
}
startActivityForResult(intent, 56)
}
}
}
override fun initData() {
//getList()
var dataStr = PreferencesUtils.getString(this, Const.MESSAGE,"[]")
var models = Gson().fromJson<List<CustomerMessageModel.MessageItemModel>>(dataStr,object : TypeToken<List<CustomerMessageModel.MessageItemModel>>(){}.type)
var data2 = models.stream().filter { it-> !TextUtils.isEmpty(it.url) || !TextUtils.isEmpty(it.content) }.toList()
data.addAll(data2)
}
fun handleMessage(){
if (data.size > 0){
var model = data.last()
var isResend = false
var sendConetnt = ""
if (model.senderId == CKApp.app.userInfo?.id){
isResend = true
if (!TextUtils.isEmpty(model.url)){
url = model.url.toString()
}else{
sendConetnt = model.content.toString()
}
}else{
if (model.content!!.indexOf("不能替代兽医诊断") < 0){
isResend = true
if (data.size - 2 >= 0){
if (!TextUtils.isEmpty(model.url)){
url = data.get(data.size - 2).url.toString()
}else{
sendConetnt = data.get(data.size - 2).content.toString()
}
}
data.removeAt(data.size -1)
}
}
if (isResend){
customerMessageAdapter.data =data
customerMessageAdapter.notifyDataSetChanged()
if (!TextUtils.isEmpty(sendConetnt) || !TextUtils.isEmpty(url)){
handler.post {
sendMessage2(UUID.randomUUID().toString(),sendConetnt,true, url)
}
}
}
}
}
var handler = object : Handler(Looper.getMainLooper()){
}
override fun rightButton1OnClick() {
CKAlertDialog(this,getString(R.string.alert),getString(R.string.clear_alert),object : CKAlertDialog.AlertClickListener{
override fun onBack(isConfirm: Boolean) {
if (isConfirm){
lock = true
PreferencesUtils.putString(this@CustomerActivity_copy, Const.MESSAGE,"[]")
data.clear()
customerMessageAdapter.data = data
customerMessageAdapter.notifyDataSetChanged()
}
}
}).show()
}
fun sendMessage(uuid :String ,content: String,isResend : Boolean, imageUrl: String) {
isAiResponding = true
if (!TextUtils.isEmpty(imageUrl)) {
this@CustomerActivity_copy.data.add(CustomerMessageModel.MessageItemModel().apply {
senderId = CKApp.app.userInfo?.id!!
this.content = content
this.senderAvatar = CKApp.app.userInfo?.avatar
this.senderName = CKApp.app.userInfo?.custName ?: ""
this.url = imageUrl
})
}
if (!TextUtils.isEmpty(content) && !isResend) {
this@CustomerActivity_copy.data.add(CustomerMessageModel.MessageItemModel().apply {
senderId = CKApp.app.userInfo?.id!!
this.content = content
this.senderAvatar = CKApp.app.userInfo?.avatar
this.senderName = CKApp.app.userInfo?.custName ?: ""
})
}
this@CustomerActivity_copy.data.add(CustomerMessageModel.MessageItemModel().apply {
senderId = -1
this.content = ""
this.senderName = getString(R.string.ai_doctor)
this.uuid = uuid
})
TTHttpClient.postJsonStream3(this, "发送会话消息stream", TTRequestParam().apply {
add(TTRequestData("imageUrl", imageUrl))
add(TTRequestData("question", content))
}, object : ICallback {
override fun onSuccess(data: String) {
// var model = Gson().fromJson<AIMessageModel>(data, AIMessageModel::class.java)
var flag = false
for (i in 0..this@CustomerActivity_copy.data.size -1){
if (this@CustomerActivity_copy.data.get(i).uuid.equals(uuid)){
flag = true
this@CustomerActivity_copy.data.get(i).content = CKUtils.subMessage(this@CustomerActivity_copy.data.get(i).content + data)
}
}
if (!flag){
this@CustomerActivity_copy.data.add(CustomerMessageModel.MessageItemModel().apply {
senderId = -1
this.content =data
// this.senderAvatar = CKApp.app.userInfo?.avatar
this.senderName = getString(R.string.ai_doctor)
this.uuid = uuid
})
}
customerMessageAdapter.data = this@CustomerActivity_copy.data
customerMessageAdapter.notifyDataSetChanged()
if (this@CustomerActivity_copy.data.last().content!!.indexOf("不能替代兽医诊断") > 0) {
binding.recyclerView.scrollToPosition(this@CustomerActivity_copy.data.size - 1)
binding.recyclerView.post {
if (customerMessageAdapter.itemCount > 0) {
val lastView = binding.recyclerView.layoutManager?.findViewByPosition(customerMessageAdapter.itemCount - 1)
lastView?.let {
val bottomOffset = it.bottom - binding.recyclerView.height
binding.recyclerView.scrollBy(0, bottomOffset)
}
}
}
}
}
override fun onFailed(code: String, msg: String) {
isAiResponding = false
lock = true
// toast(msg)
//TTLog.e(msg)
}
override fun onComplete() {
isAiResponding = false
lock = true
}
})
customerMessageAdapter.data = this@CustomerActivity_copy.data
customerMessageAdapter.notifyDataSetChanged()
binding.recyclerView.scrollToPosition(this@CustomerActivity_copy.data.size - 1)
}
fun sendMessage2(uuid :String ,content: String,isResend : Boolean, imageUrl: String) {
isAiResponding = true
lock = false
if (!TextUtils.isEmpty(content) && !isResend) {
this@CustomerActivity_copy.data.add(CustomerMessageModel.MessageItemModel().apply {
senderId = CKApp.app.userInfo?.id!!
this.content = content
this.senderAvatar = CKApp.app.userInfo?.avatar
this.senderName = CKApp.app.userInfo?.custName ?: ""
})
}
this@CustomerActivity_copy.data.add(CustomerMessageModel.MessageItemModel().apply {
senderId = -1
this.content = ""
this.senderName = getString(R.string.ai_doctor)
this.uuid = uuid
})
TTHttpClient.postJsonStream3(this, "发送会话消息stream", TTRequestParam().apply {
add(TTRequestData("imageUrl", imageUrl))
add(TTRequestData("question", content))
}, object : ICallback {
override fun onSuccess(data: String) {
// var model = Gson().fromJson<AIMessageModel>(data, AIMessageModel::class.java)
var flag = false
for (i in 0..this@CustomerActivity_copy.data.size -1){
if (this@CustomerActivity_copy.data.get(i).uuid.equals(uuid)){
flag = true
this@CustomerActivity_copy.data.get(i).content = CKUtils.subMessage(this@CustomerActivity_copy.data.get(i).content + data)
}
}
if (!flag){
this@CustomerActivity_copy.data.add(CustomerMessageModel.MessageItemModel().apply {
senderId = -1
this.content =data
// this.senderAvatar = CKApp.app.userInfo?.avatar
this.senderName = getString(R.string.ai_doctor)
this.uuid = uuid
})
}
customerMessageAdapter.data = this@CustomerActivity_copy.data
customerMessageAdapter.notifyDataSetChanged()
if (this@CustomerActivity_copy.data.last().content!!.indexOf("不能替代兽医诊断") > 0) {
binding.recyclerView.scrollToPosition(this@CustomerActivity_copy.data.size - 1)
binding.recyclerView.post {
if (customerMessageAdapter.itemCount > 0) {
val lastView = binding.recyclerView.layoutManager?.findViewByPosition(customerMessageAdapter.itemCount - 1)
lastView?.let {
val bottomOffset = it.bottom - binding.recyclerView.height
binding.recyclerView.scrollBy(0, bottomOffset)
}
}
}
}
}
override fun onFailed(code: String, msg: String) {
isAiResponding = false
lock = true
// toast(msg)
//TTLog.e(msg)
}
override fun onComplete() {
isAiResponding = false
lock = true
}
})
customerMessageAdapter.data = this@CustomerActivity_copy.data
customerMessageAdapter.notifyDataSetChanged()
binding.recyclerView.scrollToPosition(this@CustomerActivity_copy.data.size - 1)
}
fun uploadImage(content: String, imagePath: String) {
var param = TTRequestParam()
param.files.add(File(imagePath))
showProgeassDialog()
TTHttpClient.postFile(this, "上传照片s", param, object : ICallback {
override fun onSuccess(data: String) {
hiddenProgeassDialog()
var model = Gson().fromJson<UploadModel>(data, UploadModel::class.java)
handler.post {
sendMessage(UUID.randomUUID().toString(), content, false, model.urls)
}
}
override fun onFailed(code: String, msg: String) {
hiddenProgeassDialog()
lock = true
if (path.isEmpty() && binding.editMessage.text.toString().isEmpty()) {
path = imagePath
showImagePreview(imagePath)
binding.editMessage.setText(content)
}
toast(msg)
}
})
}
fun getList() {
TTHttpClient.get(this, "会话消息列表", TTRequestParam(), object : ICallback {
override fun onSuccess(data: String) {
// var model = Gson().fromJson<CustomerMessageModel>(data,CustomerMessageModel::class.java)
// model.rows?.let {
// this@CustomerActivity.data.addAll(model.rows!!)
// }
var model = Gson().fromJson<List<CustomerMessageModel.MessageItemModel>>(
data,
object : TypeToken<List<CustomerMessageModel.MessageItemModel>>() {}.type
)
this@CustomerActivity_copy.data.addAll(model)
customerMessageAdapter.data = this@CustomerActivity_copy.data
customerMessageAdapter.notifyDataSetChanged()
}
override fun onFailed(code: String, msg: String) {
}
})
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 55 && resultCode == RESULT_OK) {
path = PreferencesUtils.getString(this@CustomerActivity_copy, Const.IMAGE_PATH, "")!!
prepareSelectedImage()
} else if (requestCode == 56 && resultCode == RESULT_OK) {
path = TTUtils.getImageUrl(this, data!!.getData());
prepareSelectedImage()
}
}
private fun prepareSelectedImage() {
if (TextUtils.isEmpty(path)) return
LubanCompressUtil.getCompressFile(
this,
File(path),
object : LubanCompressUtil.CompressCallback {
override fun success(file: File) {
if (isFinishing || isDestroyed) return
path = file.absolutePath
lock = true
binding.contentBottom.visibility = View.GONE
showImagePreview(path)
binding.editMessage.requestFocus()
KeyboardUtils.showKeyboard(binding.editMessage)
// Rebind the IME after selecting an image so its action button is
// available even though the text field itself is empty.
binding.editMessage.postDelayed({
val imm = getSystemService(INPUT_METHOD_SERVICE) as? InputMethodManager
imm?.restartInput(binding.editMessage)
}, 150L)
}
override fun fail(failMsg: String) {
if (isFinishing || isDestroyed) return
lock = true
path = ""
toast(failMsg)
}
}
)
}
private fun showImagePreview(imagePath: String) {
isSending = false
binding.contentImagePreview.visibility = View.VISIBLE
updateSendControls()
binding.imagePreview.scaleType = ImageView.ScaleType.CENTER_CROP
Glide.with(this)
.load(imagePath)
.into(binding.imagePreview)
}
private fun clearSelectedImage() {
path = ""
url = ""
binding.imagePreview.setImageDrawable(null)
binding.contentImagePreview.visibility = View.GONE
updateSendControls()
}
private fun clearInputViews() {
binding.editMessage.setText("")
path = ""
url = ""
binding.imagePreview.setImageDrawable(null)
binding.contentImagePreview.visibility = View.GONE
// Sending has already been initiated; keep the controls in their idle state
// until the user starts composing the next draft.
binding.btnSend.visibility = View.GONE
binding.btnMore.visibility = View.VISIBLE
}
private fun updateSendControls() {
val hasImage = path.isNotEmpty()
val hasText = binding.editMessage.text.toString().trim().isNotEmpty()
if (isSending) {
binding.btnSend.visibility = View.GONE
binding.btnMore.visibility = View.VISIBLE
return
}
binding.btnSend.visibility = if (hasImage || hasText) View.VISIBLE else View.GONE
binding.btnMore.visibility = if (hasImage) View.GONE else View.VISIBLE
}
override fun onDestroy() {
super.onDestroy()
PreferencesUtils.putString(this, Const.MESSAGE,Gson().toJson(data))
}
fun takePhoto() {
try {
val openCameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
val vFile = File(
getExternalFilesDir(Environment.DIRECTORY_PICTURES),
"${System.currentTimeMillis()}.png"
)
val parentDir = vFile.parentFile
if (parentDir != null && !parentDir.exists()) {
parentDir.mkdirs()
}
TTLog.e(vFile.absolutePath)
PreferencesUtils.putString(getApplicationContext(), Const.IMAGE_PATH, vFile.absolutePath)
val cameraUri: Uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
FileProvider.getUriForFile(
this@CustomerActivity_copy,
packageName + ".fileprovider",
vFile
)
} else {
Uri.fromFile(vFile)
}
openCameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, cameraUri)
startActivityForResult(openCameraIntent, 55)
}catch (e: Exception){
e.printStackTrace()
}
}
class CustomerMessageAdapter(
var context: TTBaseActivity,
var data: List<CustomerMessageModel.MessageItemModel>,
var onItemClickListenner: OnItemClickListenner
) : RecyclerView.Adapter<CustomerMessageAdapter.CustomerMessageHolder>() {
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): CustomerMessageHolder {
return CustomerMessageHolder(
LayoutItemAiCustomerMessageBinding.inflate(
LayoutInflater.from(
context
), parent, false
)
)
}
override fun onBindViewHolder(
holder: CustomerMessageHolder,
position: Int
) {
// holder.binding.text.text = data.get(position).name
var model = data.get(position)
if (model.senderId != CKApp.app.userInfo?.id) {
holder.binding.contentTo.visibility = View.GONE
holder.binding.contentFrom.visibility = View.VISIBLE
holder.binding.textFrom.text = model.content
holder.binding.textFromNick.text = model.senderName
Glide.with(context)
.load(model.senderAvatar)
.placeholder(R.mipmap.image_ai_doctor)
.into(holder.binding.imageFrom)
holder.binding.imageContentTo.setOnClickListener(imageClick)
if (TextUtils.isEmpty(model.content)){
holder.binding.textFrom.visibility= View.GONE
holder.binding.progress.visibility= View.VISIBLE
}else{
holder.binding.textFrom.visibility= View.VISIBLE
holder.binding.progress.visibility= View.GONE
}
} else {
holder.binding.contentTo.visibility = View.VISIBLE
holder.binding.contentFrom.visibility = View.GONE
holder.binding.textTo.text = model.content
holder.binding.textToNick.text = model.senderName
Glide.with(context)
.load(model.senderAvatar)
.placeholder(R.mipmap.image_default)
.into(holder.binding.imageTo)
if (!TextUtils.isEmpty(model.url)) {
holder.binding.textTo.visibility = View.GONE
holder.binding.imageContentTo.visibility = View.VISIBLE
val imageView = holder.binding.imageContentTo
val imageUrl = model.url!!
imageView.setTag(imageUrl)
resetImageContentSize(imageView)
Glide.with(context)
.load(imageUrl)
.placeholder(R.mipmap.image_default)
.listener(object : RequestListener<Drawable> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable>?,
isFirstResource: Boolean
): Boolean = false
override fun onResourceReady(
resource: Drawable,
model: Any,
target: Target<Drawable>?,
dataSource: DataSource,
isFirstResource: Boolean
): Boolean {
if (imageView.tag == imageUrl) {
setImageContentSize(
imageView,
resource.intrinsicWidth,
resource.intrinsicHeight
)
}
return false
}
})
.into(imageView)
imageView.setOnClickListener(imageClick)
} else {
holder.binding.textTo.visibility = View.VISIBLE
holder.binding.imageContentTo.visibility = View.GONE
}
}
holder.binding.root.setTag(position)
holder.binding.root.setOnClickListener {
val position = it.tag as Int
onItemClickListenner.onClick(position, data.get(position))
}
}
private fun resetImageContentSize(imageView: View) {
val density = imageView.resources.displayMetrics.density
imageView.layoutParams = imageView.layoutParams.apply {
width = getMaxImageWidth(density)
height = (200 * density).toInt()
}
}
private fun setImageContentSize(imageView: View, sourceWidth: Int, sourceHeight: Int) {
if (sourceWidth <= 0 || sourceHeight <= 0) return
val density = imageView.resources.displayMetrics.density
val maxWidth = getMaxImageWidth(density).toFloat()
val maxHeight = (200 * density).toFloat()
val scale = minOf(
1f,
maxWidth / sourceWidth.toFloat(),
maxHeight / sourceHeight.toFloat()
)
imageView.layoutParams = imageView.layoutParams.apply {
width = (sourceWidth * scale).toInt().coerceAtLeast(1)
height = (sourceHeight * scale).toInt().coerceAtLeast(1)
}
}
private fun getMaxImageWidth(density: Float): Int {
val requestedWidth = (200 * density).toInt()
// Reserve the avatar, paddings, and the bubble's left inset.
val availableWidth = context.resources.displayMetrics.widthPixels - (155 * density).toInt()
return minOf(requestedWidth, availableWidth.coerceAtLeast(1))
}
override fun getItemCount(): Int {
return data.size
}
class CustomerMessageHolder(var binding: LayoutItemAiCustomerMessageBinding) :
RecyclerView.ViewHolder(binding.root) {
}
var imageClick = object : View.OnClickListener{
override fun onClick(v: View?) {
var url = v?.tag as String
var urls = mutableListOf<String>()
var n = 0
var pos = 0
for (m in data){
if (!TextUtils.isEmpty(m.url)){
urls.add(m.url!!)
if (url.equals(m.url)){
pos = n
}
n++
}
}
context.toActivity(ImageViewActivity::class.java, DataCollection().apply {
add(Data("data",Gson().toJson(urls)))
add(Data("pos",pos.toString()))
})
}
}
}
companion object {
private const val REQUEST_CAMERA_PERMISSION = 1001
private const val REQUEST_PHOTO_PERMISSION = 1002
}
}

View File

@@ -1,5 +1,6 @@
package com.ck.ckcollar.app.ui.act.customer package com.ck.ckcollar.app.ui.act.customer
import android.Manifest
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
@@ -36,6 +37,7 @@ import com.ck.ckcollar.app.model.CustomerMessageModel
import com.ck.ckcollar.app.model.UploadModel import com.ck.ckcollar.app.model.UploadModel
import com.ck.ckcollar.app.ui.base.CKBaseActivity import com.ck.ckcollar.app.ui.base.CKBaseActivity
import com.ck.ckcollar.app.utils.Const import com.ck.ckcollar.app.utils.Const
import com.ck.ckcollar.app.utils.LubanCompressUtil
import com.ck.ckcollar.app.utils.networkone.ICallback import com.ck.ckcollar.app.utils.networkone.ICallback
import com.ck.ckcollar.app.utils.networkone.TTHttpClient import com.ck.ckcollar.app.utils.networkone.TTHttpClient
import com.ck.ckcollar.app.utils.networkone.model.TTRequestData import com.ck.ckcollar.app.utils.networkone.model.TTRequestData
@@ -64,6 +66,7 @@ class MineCustomerActivity : CKBaseActivity() {
var path = "" var path = ""
var url = "" var url = ""
private var imageSendDraft = ""
var lock = true var lock = true
var webSocket: WebSocket? = null var webSocket: WebSocket? = null
@@ -98,6 +101,13 @@ class MineCustomerActivity : CKBaseActivity() {
binding.editMessage.setHorizontallyScrolling(false); binding.editMessage.setHorizontallyScrolling(false);
binding.editMessage.setOnClickListener {
binding.contentBottom.visibility = View.GONE
}
binding.editMessage.onFocusChangeListener = View.OnFocusChangeListener { _, hasFocus ->
if (hasFocus) binding.contentBottom.visibility = View.GONE
}
binding.editMessage.setOnEditorActionListener(object : TextView.OnEditorActionListener { binding.editMessage.setOnEditorActionListener(object : TextView.OnEditorActionListener {
override fun onEditorAction( override fun onEditorAction(
p0: TextView?, p0: TextView?,
@@ -120,6 +130,7 @@ class MineCustomerActivity : CKBaseActivity() {
sendMessage(text) sendMessage(text)
} }
} }
return true
} }
return false return false
} }
@@ -157,7 +168,9 @@ class MineCustomerActivity : CKBaseActivity() {
}) })
binding.btnMore.setOnClickListener { binding.btnMore.setOnClickListener {
if (binding.contentBottom.visibility == View.GONE) { if (binding.contentBottom.visibility == View.GONE) {
KeyboardUtils.hideKeyboard(this@MineCustomerActivity) val inputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as android.view.inputmethod.InputMethodManager
inputMethodManager.hideSoftInputFromWindow(binding.editMessage.windowToken, 0)
binding.editMessage.clearFocus()
binding.contentBottom.visibility = View.VISIBLE binding.contentBottom.visibility = View.VISIBLE
} else { } else {
binding.contentBottom.visibility = View.GONE binding.contentBottom.visibility = View.GONE
@@ -167,13 +180,17 @@ class MineCustomerActivity : CKBaseActivity() {
} }
binding.btnSmile.setOnClickListener { binding.btnSmile.setOnClickListener {
binding.contentBottom.visibility = View.GONE
binding.editMessage.requestFocus() binding.editMessage.requestFocus()
KeyboardUtils.showKeyboard(binding.editMessage) KeyboardUtils.showKeyboard(binding.editMessage)
} }
binding.conetnt1.setOnClickListener { binding.conetnt1.setOnClickListener {
if (TextUtils.isEmpty(path)) { if (TextUtils.isEmpty(path)) {
takePhoto() getPermissionRequst(
Manifest.permission.CAMERA,
REQUEST_CAMERA_PERMISSION
)
} else { } else {
toast(getString(R.string.only_one_photo)) toast(getString(R.string.only_one_photo))
} }
@@ -181,12 +198,12 @@ class MineCustomerActivity : CKBaseActivity() {
} }
binding.conetnt2.setOnClickListener { binding.conetnt2.setOnClickListener {
if (TextUtils.isEmpty(path)) { if (TextUtils.isEmpty(path)) {
//相册 val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
val i = Intent( Manifest.permission.READ_MEDIA_IMAGES
Intent.ACTION_PICK, } else {
MediaStore.Images.Media.EXTERNAL_CONTENT_URI Manifest.permission.READ_EXTERNAL_STORAGE
) }
startActivityForResult(i, 56) getPermissionRequst(permission, REQUEST_PHOTO_PERMISSION)
} else { } else {
toast(getString(R.string.only_one_photo)) toast(getString(R.string.only_one_photo))
} }
@@ -195,6 +212,23 @@ class MineCustomerActivity : CKBaseActivity() {
} }
override fun onPermissionsGranted(requestCode: Int, permissions: Array<String>) {
when (requestCode) {
REQUEST_CAMERA_PERMISSION -> takePhoto()
REQUEST_PHOTO_PERMISSION -> openPhotoAlbum()
}
}
private fun openPhotoAlbum() {
val intent = Intent(
Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
).apply {
setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*")
}
startActivityForResult(intent, 56)
}
override fun initData() { override fun initData() {
//getList() //getList()
@@ -262,7 +296,7 @@ class MineCustomerActivity : CKBaseActivity() {
override fun onOpen(webSocket: WebSocket, response: Response) { override fun onOpen(webSocket: WebSocket, response: Response) {
TTLog.e("onOpen") TTLog.e("onOpen")
runOnUiThread { runOnUiThread {
toast(getString(R.string.connect_customer_success)) // toast(getString(R.string.connect_customer_success))
} }
} }
}) })
@@ -280,7 +314,9 @@ class MineCustomerActivity : CKBaseActivity() {
fun sendMessage(content: String) { fun sendMessage(content: String) {
if (!TextUtils.isEmpty(url)) {
showProgeassDialog(getString(R.string.send)) showProgeassDialog(getString(R.string.send))
}
TTHttpClient.postJson(this, "发送人工会话消息", TTRequestParam().apply { TTHttpClient.postJson(this, "发送人工会话消息", TTRequestParam().apply {
add(TTRequestData("content", content)) add(TTRequestData("content", content))
add(TTRequestData("chatType", 2)) add(TTRequestData("chatType", 2))
@@ -309,7 +345,8 @@ class MineCustomerActivity : CKBaseActivity() {
binding.editMessage.setText("") binding.editMessage.setText(if (!TextUtils.isEmpty(url)) imageSendDraft else "")
imageSendDraft = ""
path = "" path = ""
url = "" url = ""
customerMessageAdapter.data = this@MineCustomerActivity.data customerMessageAdapter.data = this@MineCustomerActivity.data
@@ -341,7 +378,7 @@ class MineCustomerActivity : CKBaseActivity() {
var model = Gson().fromJson<UploadModel>(data, UploadModel::class.java) var model = Gson().fromJson<UploadModel>(data, UploadModel::class.java)
url = model.urls url = model.urls
imageSendDraft = binding.editMessage.text.toString().replace("$$$$$", "")
sendMessage(url) sendMessage(url)
} }
@@ -428,15 +465,33 @@ class MineCustomerActivity : CKBaseActivity() {
if (requestCode == 55 && resultCode == RESULT_OK) { if (requestCode == 55 && resultCode == RESULT_OK) {
path = PreferencesUtils.getString(this@MineCustomerActivity, Const.IMAGE_PATH, "")!! path = PreferencesUtils.getString(this@MineCustomerActivity, Const.IMAGE_PATH, "")!!
compressAndUploadImage()
//addImage(path!!)
uploadImage()
} else if (requestCode == 56 && resultCode == RESULT_OK) { } else if (requestCode == 56 && resultCode == RESULT_OK) {
path = TTUtils.getImageUrl(this, data!!.getData()); path = TTUtils.getImageUrl(this, data!!.getData());
// addImage(path) compressAndUploadImage()
}
}
private fun compressAndUploadImage() {
if (TextUtils.isEmpty(path)) return
LubanCompressUtil.getCompressFile(
this,
File(path),
object : LubanCompressUtil.CompressCallback {
override fun success(file: File) {
if (isFinishing || isDestroyed) return
path = file.absolutePath
uploadImage() uploadImage()
} }
override fun fail(failMsg: String) {
if (isFinishing || isDestroyed) return
path = ""
toast(failMsg)
}
}
)
} }
override fun onDestroy() { override fun onDestroy() {
@@ -476,6 +531,11 @@ class MineCustomerActivity : CKBaseActivity() {
startActivityForResult(openCameraIntent, 55) startActivityForResult(openCameraIntent, 55)
} }
companion object {
private const val REQUEST_CAMERA_PERMISSION = 1201
private const val REQUEST_PHOTO_PERMISSION = 1202
}
class CustomerMessageAdapter( class CustomerMessageAdapter(
var context: Context, var context: Context,
var data: List<CustomerMessageModel.MessageItemModel>, var data: List<CustomerMessageModel.MessageItemModel>,
@@ -528,10 +588,11 @@ class MineCustomerActivity : CKBaseActivity() {
holder.binding.textTo.visibility = View.GONE holder.binding.textTo.visibility = View.GONE
holder.binding.imageContentTo.visibility = View.VISIBLE holder.binding.imageContentTo.visibility = View.VISIBLE
Glide.with(context) ChatImageLoader.load(
.load(ActionCode.BASE_URL + model.url) context,
.placeholder(R.mipmap.image_default) holder.binding.imageContentTo,
.into(holder.binding.imageContentTo) ActionCode.BASE_URL + model.url
)
} else { } else {
holder.binding.textTo.visibility = View.VISIBLE holder.binding.textTo.visibility = View.VISIBLE
holder.binding.imageContentTo.visibility = View.GONE holder.binding.imageContentTo.visibility = View.GONE

View File

@@ -1,5 +1,6 @@
package com.ck.ckcollar.app.ui.act.customer package com.ck.ckcollar.app.ui.act.customer
import android.Manifest
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.Rect import android.graphics.Rect
@@ -45,6 +46,7 @@ import com.ck.ckcollar.app.ui.base.CKBaseActivity
import com.ck.ckcollar.app.ui.dialog.CKAlertDialog import com.ck.ckcollar.app.ui.dialog.CKAlertDialog
import com.ck.ckcollar.app.utils.CKUtils import com.ck.ckcollar.app.utils.CKUtils
import com.ck.ckcollar.app.utils.Const import com.ck.ckcollar.app.utils.Const
import com.ck.ckcollar.app.utils.LubanCompressUtil
import com.ck.ckcollar.app.utils.networkone.ICallback import com.ck.ckcollar.app.utils.networkone.ICallback
import com.ck.ckcollar.app.utils.networkone.TTHttpClient import com.ck.ckcollar.app.utils.networkone.TTHttpClient
import com.ck.ckcollar.app.utils.networkone.model.TTRequestData import com.ck.ckcollar.app.utils.networkone.model.TTRequestData
@@ -76,6 +78,7 @@ class PeopleCustomerActivity : CKBaseActivity() {
var path = "" var path = ""
var url = "" var url = ""
private var imageSendDraft = ""
var lock = true var lock = true
var webSocket: WebSocket? = null var webSocket: WebSocket? = null
@@ -154,6 +157,7 @@ class PeopleCustomerActivity : CKBaseActivity() {
sendMessage(text) sendMessage(text)
} }
} }
return true
} }
return false return false
} }
@@ -191,7 +195,9 @@ class PeopleCustomerActivity : CKBaseActivity() {
}) })
binding.btnMore.setOnClickListener { binding.btnMore.setOnClickListener {
if (binding.contentBottom.visibility == View.GONE) { if (binding.contentBottom.visibility == View.GONE) {
KeyboardUtils.hideKeyboard(this@PeopleCustomerActivity) val inputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as android.view.inputmethod.InputMethodManager
inputMethodManager.hideSoftInputFromWindow(binding.editMessage.windowToken, 0)
binding.editMessage.clearFocus()
binding.contentBottom.visibility = View.VISIBLE binding.contentBottom.visibility = View.VISIBLE
} else { } else {
binding.contentBottom.visibility = View.GONE binding.contentBottom.visibility = View.GONE
@@ -203,6 +209,7 @@ class PeopleCustomerActivity : CKBaseActivity() {
} }
binding.btnSmile.setOnClickListener { binding.btnSmile.setOnClickListener {
binding.contentBottom.visibility = View.GONE
binding.editMessage.requestFocus() binding.editMessage.requestFocus()
KeyboardUtils.showKeyboard(binding.editMessage) KeyboardUtils.showKeyboard(binding.editMessage)
handler2.sendEmptyMessageDelayed(0,300) handler2.sendEmptyMessageDelayed(0,300)
@@ -211,16 +218,10 @@ class PeopleCustomerActivity : CKBaseActivity() {
binding.conetnt1.setOnClickListener { binding.conetnt1.setOnClickListener {
if (TextUtils.isEmpty(path)) { if (TextUtils.isEmpty(path)) {
if (!checkCameraPermissions()){ getPermissionRequst(
CKAlertDialog(this@PeopleCustomerActivity,getString(R.string.alert),getString(R.string.camera_alert),object : CKAlertDialog.AlertClickListener{ Manifest.permission.CAMERA,
override fun onBack(isConfirm: Boolean) { REQUEST_CAMERA_PERMISSION
TODO("Not yet implemented") )
}
}).show()
return@setOnClickListener
}
takePhoto()
} else { } else {
toast(getString(R.string.only_one_photo)) toast(getString(R.string.only_one_photo))
} }
@@ -228,12 +229,12 @@ class PeopleCustomerActivity : CKBaseActivity() {
} }
binding.conetnt2.setOnClickListener { binding.conetnt2.setOnClickListener {
if (TextUtils.isEmpty(path)) { if (TextUtils.isEmpty(path)) {
//相册 val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
val i = Intent( Manifest.permission.READ_MEDIA_IMAGES
Intent.ACTION_PICK, } else {
MediaStore.Images.Media.EXTERNAL_CONTENT_URI Manifest.permission.READ_EXTERNAL_STORAGE
) }
startActivityForResult(i, 56) getPermissionRequst(permission, REQUEST_PHOTO_PERMISSION)
} else { } else {
toast(getString(R.string.only_one_photo)) toast(getString(R.string.only_one_photo))
} }
@@ -243,6 +244,23 @@ class PeopleCustomerActivity : CKBaseActivity() {
} }
override fun onPermissionsGranted(requestCode: Int, permissions: Array<String>) {
when (requestCode) {
REQUEST_CAMERA_PERMISSION -> takePhoto()
REQUEST_PHOTO_PERMISSION -> openPhotoAlbum()
}
}
private fun openPhotoAlbum() {
val intent = Intent(
Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
).apply {
setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*")
}
startActivityForResult(intent, 56)
}
override fun initData() { override fun initData() {
@@ -353,7 +371,7 @@ class PeopleCustomerActivity : CKBaseActivity() {
override fun onOpen(webSocket: WebSocket, response: Response) { override fun onOpen(webSocket: WebSocket, response: Response) {
TTLog.e("onOpen") TTLog.e("onOpen")
runOnUiThread { runOnUiThread {
toast(getString(R.string.connect_customer_success)) // toast(getString(R.string.connect_customer_success))
} }
} }
}) })
@@ -394,7 +412,9 @@ class PeopleCustomerActivity : CKBaseActivity() {
"<img src=\"$content\"/>" "<img src=\"$content\"/>"
} }
if (!TextUtils.isEmpty(url)) {
showProgeassDialog(getString(R.string.send)) showProgeassDialog(getString(R.string.send))
}
TTHttpClient.postJson(this, "发送人工会话消息", TTRequestParam().apply { TTHttpClient.postJson(this, "发送人工会话消息", TTRequestParam().apply {
add(TTRequestData("content", sendContent)) add(TTRequestData("content", sendContent))
add(TTRequestData("chatType", chatType)) add(TTRequestData("chatType", chatType))
@@ -422,7 +442,8 @@ class PeopleCustomerActivity : CKBaseActivity() {
binding.editMessage.setText("") binding.editMessage.setText(if (!TextUtils.isEmpty(url)) imageSendDraft else "")
imageSendDraft = ""
path = "" path = ""
url = "" url = ""
customerMessageAdapter.data = this@PeopleCustomerActivity.data customerMessageAdapter.data = this@PeopleCustomerActivity.data
@@ -454,7 +475,7 @@ class PeopleCustomerActivity : CKBaseActivity() {
var model = Gson().fromJson<UploadModel>(data, UploadModel::class.java) var model = Gson().fromJson<UploadModel>(data, UploadModel::class.java)
url = model.urls url = model.urls
imageSendDraft = binding.editMessage.text.toString().replace("$$$$$", "")
sendMessage(url) sendMessage(url)
} }
@@ -559,15 +580,33 @@ class PeopleCustomerActivity : CKBaseActivity() {
if (requestCode == 55 && resultCode == RESULT_OK) { if (requestCode == 55 && resultCode == RESULT_OK) {
path = PreferencesUtils.getString(this@PeopleCustomerActivity, Const.IMAGE_PATH, "")!! path = PreferencesUtils.getString(this@PeopleCustomerActivity, Const.IMAGE_PATH, "")!!
compressAndUploadImage()
//addImage(path!!)
uploadImage()
} else if (requestCode == 56 && resultCode == RESULT_OK) { } else if (requestCode == 56 && resultCode == RESULT_OK) {
path = TTUtils.getImageUrl(this, data!!.getData()); path = TTUtils.getImageUrl(this, data!!.getData());
//addImage(path) compressAndUploadImage()
}
}
private fun compressAndUploadImage() {
if (TextUtils.isEmpty(path)) return
LubanCompressUtil.getCompressFile(
this,
File(path),
object : LubanCompressUtil.CompressCallback {
override fun success(file: File) {
if (isFinishing || isDestroyed) return
path = file.absolutePath
uploadImage() uploadImage()
} }
override fun fail(failMsg: String) {
if (isFinishing || isDestroyed) return
path = ""
toast(failMsg)
}
}
)
} }
override fun onDestroy() { override fun onDestroy() {
@@ -607,6 +646,11 @@ class PeopleCustomerActivity : CKBaseActivity() {
startActivityForResult(openCameraIntent, 55) startActivityForResult(openCameraIntent, 55)
} }
companion object {
private const val REQUEST_CAMERA_PERMISSION = 1301
private const val REQUEST_PHOTO_PERMISSION = 1302
}
class CustomerMessageAdapter( class CustomerMessageAdapter(
var context: TTBaseActivity, var context: TTBaseActivity,
var data: List<CustomerMessageModel.MessageItemModel>, var data: List<CustomerMessageModel.MessageItemModel>,
@@ -675,10 +719,7 @@ class PeopleCustomerActivity : CKBaseActivity() {
holder.binding.textTo.visibility = View.GONE holder.binding.textTo.visibility = View.GONE
holder.binding.imageContentTo.visibility = View.VISIBLE holder.binding.imageContentTo.visibility = View.VISIBLE
Glide.with(context) ChatImageLoader.load(context, holder.binding.imageContentTo, model.url!!)
.load( model.url)
.placeholder(R.mipmap.image_default)
.into(holder.binding.imageContentTo)
holder.binding.imageContentTo.setTag(model.url) holder.binding.imageContentTo.setTag(model.url)

View File

@@ -1,5 +1,6 @@
package com.ck.ckcollar.app.ui.act.customer package com.ck.ckcollar.app.ui.act.customer
import android.Manifest
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
@@ -36,6 +37,7 @@ import com.ck.ckcollar.app.model.CustomerMessageModel
import com.ck.ckcollar.app.model.UploadModel import com.ck.ckcollar.app.model.UploadModel
import com.ck.ckcollar.app.ui.base.CKBaseActivity import com.ck.ckcollar.app.ui.base.CKBaseActivity
import com.ck.ckcollar.app.utils.Const import com.ck.ckcollar.app.utils.Const
import com.ck.ckcollar.app.utils.LubanCompressUtil
import com.ck.ckcollar.app.utils.networkone.ICallback import com.ck.ckcollar.app.utils.networkone.ICallback
import com.ck.ckcollar.app.utils.networkone.TTHttpClient import com.ck.ckcollar.app.utils.networkone.TTHttpClient
import com.ck.ckcollar.app.utils.networkone.model.TTRequestData import com.ck.ckcollar.app.utils.networkone.model.TTRequestData
@@ -58,12 +60,15 @@ import java.util.concurrent.TimeUnit
class ShopCustomerActivity : CKBaseActivity() { class ShopCustomerActivity : CKBaseActivity() {
private val requestPhotoPermission = 1402
lateinit var binding: ActivityCustomerBinding lateinit var binding: ActivityCustomerBinding
lateinit var customerMessageAdapter: CustomerMessageAdapter lateinit var customerMessageAdapter: CustomerMessageAdapter
var data = mutableListOf<CustomerMessageModel.MessageItemModel>() var data = mutableListOf<CustomerMessageModel.MessageItemModel>()
var path = "" var path = ""
var url = "" var url = ""
private var imageSendDraft = ""
var lock = true var lock = true
var webSocket: WebSocket? = null var webSocket: WebSocket? = null
@@ -97,6 +102,13 @@ class ShopCustomerActivity : CKBaseActivity() {
binding.editMessage.setHorizontallyScrolling(false); binding.editMessage.setHorizontallyScrolling(false);
binding.editMessage.setOnClickListener {
binding.contentBottom.visibility = View.GONE
}
binding.editMessage.onFocusChangeListener = View.OnFocusChangeListener { _, hasFocus ->
if (hasFocus) binding.contentBottom.visibility = View.GONE
}
binding.editMessage.setOnEditorActionListener(object : TextView.OnEditorActionListener { binding.editMessage.setOnEditorActionListener(object : TextView.OnEditorActionListener {
override fun onEditorAction( override fun onEditorAction(
p0: TextView?, p0: TextView?,
@@ -119,6 +131,7 @@ class ShopCustomerActivity : CKBaseActivity() {
sendMessage(text) sendMessage(text)
} }
} }
return true
} }
return false return false
} }
@@ -156,7 +169,9 @@ class ShopCustomerActivity : CKBaseActivity() {
}) })
binding.btnMore.setOnClickListener { binding.btnMore.setOnClickListener {
if (binding.contentBottom.visibility == View.GONE) { if (binding.contentBottom.visibility == View.GONE) {
KeyboardUtils.hideKeyboard(this@ShopCustomerActivity) val inputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as android.view.inputmethod.InputMethodManager
inputMethodManager.hideSoftInputFromWindow(binding.editMessage.windowToken, 0)
binding.editMessage.clearFocus()
binding.contentBottom.visibility = View.VISIBLE binding.contentBottom.visibility = View.VISIBLE
} else { } else {
binding.contentBottom.visibility = View.GONE binding.contentBottom.visibility = View.GONE
@@ -166,6 +181,7 @@ class ShopCustomerActivity : CKBaseActivity() {
} }
binding.btnSmile.setOnClickListener { binding.btnSmile.setOnClickListener {
binding.contentBottom.visibility = View.GONE
binding.editMessage.requestFocus() binding.editMessage.requestFocus()
KeyboardUtils.showKeyboard(binding.editMessage) KeyboardUtils.showKeyboard(binding.editMessage)
} }
@@ -181,11 +197,12 @@ class ShopCustomerActivity : CKBaseActivity() {
binding.conetnt2.setOnClickListener { binding.conetnt2.setOnClickListener {
if (TextUtils.isEmpty(path)) { if (TextUtils.isEmpty(path)) {
//相册 //相册
val i = Intent( val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
Intent.ACTION_PICK, Manifest.permission.READ_MEDIA_IMAGES
MediaStore.Images.Media.EXTERNAL_CONTENT_URI } else {
) Manifest.permission.READ_EXTERNAL_STORAGE
startActivityForResult(i, 56) }
getPermissionRequst(permission, requestPhotoPermission)
} else { } else {
toast(getString(R.string.only_one_photo)) toast(getString(R.string.only_one_photo))
} }
@@ -194,6 +211,22 @@ class ShopCustomerActivity : CKBaseActivity() {
} }
override fun onPermissionsGranted(requestCode: Int, permissions: Array<String>) {
if (requestCode == requestPhotoPermission) {
openPhotoAlbum()
}
}
private fun openPhotoAlbum() {
val intent = Intent(
Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
).apply {
setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*")
}
startActivityForResult(intent, 56)
}
override fun initData() { override fun initData() {
//getList() //getList()
@@ -261,7 +294,7 @@ class ShopCustomerActivity : CKBaseActivity() {
override fun onOpen(webSocket: WebSocket, response: Response) { override fun onOpen(webSocket: WebSocket, response: Response) {
TTLog.e("onOpen") TTLog.e("onOpen")
runOnUiThread { runOnUiThread {
toast(getString(R.string.connect_customer_success)) // toast(getString(R.string.connect_customer_success))
} }
} }
}) })
@@ -295,7 +328,9 @@ class ShopCustomerActivity : CKBaseActivity() {
// e.printStackTrace() // e.printStackTrace()
// } // }
if (!TextUtils.isEmpty(url)) {
showProgeassDialog(getString(R.string.send)) showProgeassDialog(getString(R.string.send))
}
TTHttpClient.postJson(this, "发送人工会话消息", TTRequestParam().apply { TTHttpClient.postJson(this, "发送人工会话消息", TTRequestParam().apply {
add(TTRequestData("content", content)) add(TTRequestData("content", content))
add(TTRequestData("chatType", 1)) add(TTRequestData("chatType", 1))
@@ -323,7 +358,8 @@ class ShopCustomerActivity : CKBaseActivity() {
binding.editMessage.setText("") binding.editMessage.setText(if (!TextUtils.isEmpty(url)) imageSendDraft else "")
imageSendDraft = ""
path = "" path = ""
url = "" url = ""
customerMessageAdapter.data = this@ShopCustomerActivity.data customerMessageAdapter.data = this@ShopCustomerActivity.data
@@ -355,6 +391,7 @@ class ShopCustomerActivity : CKBaseActivity() {
var model = Gson().fromJson<UploadModel>(data, UploadModel::class.java) var model = Gson().fromJson<UploadModel>(data, UploadModel::class.java)
url = model.urls url = model.urls
imageSendDraft = binding.editMessage.text.toString().replace("$$$$$", "")
sendMessage(url) sendMessage(url)
} }
@@ -441,15 +478,33 @@ class ShopCustomerActivity : CKBaseActivity() {
if (requestCode == 55 && resultCode == RESULT_OK) { if (requestCode == 55 && resultCode == RESULT_OK) {
path = PreferencesUtils.getString(this@ShopCustomerActivity, Const.IMAGE_PATH, "")!! path = PreferencesUtils.getString(this@ShopCustomerActivity, Const.IMAGE_PATH, "")!!
compressAndUploadImage()
//addImage(path!!)
uploadImage()
} else if (requestCode == 56 && resultCode == RESULT_OK) { } else if (requestCode == 56 && resultCode == RESULT_OK) {
path = TTUtils.getImageUrl(this, data!!.getData()); path = TTUtils.getImageUrl(this, data!!.getData());
//addImage(path) compressAndUploadImage()
}
}
private fun compressAndUploadImage() {
if (TextUtils.isEmpty(path)) return
LubanCompressUtil.getCompressFile(
this,
File(path),
object : LubanCompressUtil.CompressCallback {
override fun success(file: File) {
if (isFinishing || isDestroyed) return
path = file.absolutePath
uploadImage() uploadImage()
} }
override fun fail(failMsg: String) {
if (isFinishing || isDestroyed) return
path = ""
toast(failMsg)
}
}
)
} }
override fun onDestroy() { override fun onDestroy() {
@@ -541,10 +596,7 @@ class ShopCustomerActivity : CKBaseActivity() {
holder.binding.textTo.visibility = View.GONE holder.binding.textTo.visibility = View.GONE
holder.binding.imageContentTo.visibility = View.VISIBLE holder.binding.imageContentTo.visibility = View.VISIBLE
Glide.with(context) ChatImageLoader.load(context, holder.binding.imageContentTo, model.url!!)
.load( model.url)
.placeholder(R.mipmap.image_default)
.into(holder.binding.imageContentTo)
} else { } else {
holder.binding.textTo.visibility = View.VISIBLE holder.binding.textTo.visibility = View.VISIBLE
holder.binding.imageContentTo.visibility = View.GONE holder.binding.imageContentTo.visibility = View.GONE

View File

@@ -1,40 +1,64 @@
package com.ck.ckcollar.app.ui.act.home package com.ck.ckcollar.app.ui.act.home
import android.graphics.Color import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.MenuItem import android.os.SystemClock
import android.provider.Settings
import android.view.View import android.view.View
import android.view.WindowInsets import androidx.activity.OnBackPressedCallback
import android.widget.TextView import androidx.activity.result.contract.ActivityResultContracts
import androidx.viewpager2.widget.ViewPager2 import androidx.core.content.ContextCompat
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback import androidx.core.content.FileProvider
import com.ck.ckcollar.app.R import com.ck.ckcollar.app.R
import com.ck.ckcollar.app.databinding.ActivityMainBinding import com.ck.ckcollar.app.databinding.ActivityMainBinding
import com.ck.ckcollar.app.databinding.FragmentHomeBinding
import com.ck.ckcollar.app.model.CustomerStatusModel
import com.ck.ckcollar.app.model.UpdateModel import com.ck.ckcollar.app.model.UpdateModel
import com.ck.ckcollar.app.ui.act.home.adapter.MainFragmentAdapter import com.ck.ckcollar.app.ui.act.home.adapter.MainFragmentAdapter
import com.ck.ckcollar.app.ui.act.home.fragment.HealthFragment import com.ck.ckcollar.app.ui.act.home.fragment.HealthFragment
import com.ck.ckcollar.app.ui.act.home.fragment.HomeFragment import com.ck.ckcollar.app.ui.act.home.fragment.HomeFragment
import com.ck.ckcollar.app.ui.act.home.fragment.MineFragment import com.ck.ckcollar.app.ui.act.home.fragment.MineFragment
import com.ck.ckcollar.app.ui.act.home.fragment.ShopFragment import com.ck.ckcollar.app.ui.act.home.fragment.ShopFragment
import com.ck.ckcollar.app.ui.base.CKBaseActivity
import com.ck.ckcollar.app.ui.base.CKBaseFragment import com.ck.ckcollar.app.ui.base.CKBaseFragment
import com.ck.ckcollar.app.ui.base.CKLHBaseActivity import com.ck.ckcollar.app.ui.base.CKLHBaseActivity
import com.ck.ckcollar.app.ui.dialog.CKUpdateAlertDialog import com.ck.ckcollar.app.ui.dialog.CKUpdateAlertDialog
import com.ck.ckcollar.app.utils.AppUpdateDownloader
import com.ck.ckcollar.app.utils.networkone.ICallback import com.ck.ckcollar.app.utils.networkone.ICallback
import com.ck.ckcollar.app.utils.networkone.TTHttpClient import com.ck.ckcollar.app.utils.networkone.TTHttpClient
import com.ck.ckcollar.app.utils.networkone.model.TTRequestParam import com.ck.ckcollar.app.utils.networkone.model.TTRequestParam
import com.cyclone.shadowsocks.ui.frg.TTBaseFragment
import com.google.android.material.navigation.NavigationBarView
import com.google.gson.Gson import com.google.gson.Gson
import com.tt.kit.base.TTBaseActivity
import com.tt.kit.utils.TTUtils import com.tt.kit.utils.TTUtils
import java.io.File
class MainActivity : CKLHBaseActivity(),View.OnClickListener { class MainActivity : CKLHBaseActivity(),View.OnClickListener {
private var lastBackPressedAt = 0L
private var pendingUpdate: UpdateModel? = null
private var updateDialog: CKUpdateAlertDialog? = null
private var pendingApk: File? = null
private val notificationPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { granted ->
if (granted) {
pendingUpdate?.let(::startUpdateDownload)
} else {
toast(getString(R.string.notification_permission_required))
}
}
private val installPermissionLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O || packageManager.canRequestPackageInstalls()) {
pendingApk?.let(::installApk)
} else {
toast(getString(R.string.install_permission_required))
}
}
lateinit var mainBinding: ActivityMainBinding lateinit var mainBinding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@@ -43,6 +67,18 @@ class MainActivity : CKLHBaseActivity(),View.OnClickListener {
setContentView(mainBinding.root) setContentView(mainBinding.root)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
val now = SystemClock.elapsedRealtime()
if (lastBackPressedAt != 0L && now - lastBackPressedAt <= EXIT_INTERVAL_MS) {
finish()
} else {
lastBackPressedAt = now
toast(getString(R.string.press_again_to_exit))
}
}
})
// if (Build.VERSION.SDK_INT >= 36){ // if (Build.VERSION.SDK_INT >= 36){
// //
@@ -100,6 +136,22 @@ class MainActivity : CKLHBaseActivity(),View.OnClickListener {
mainBinding.viewPager.setPagingEnabled(false) mainBinding.viewPager.setPagingEnabled(false)
if (intent.getBooleanExtra(EXTRA_SHOW_HOME, false)) {
showHomeTab()
}
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
if (intent.getBooleanExtra(EXTRA_SHOW_HOME, false)) {
showHomeTab()
}
}
private fun showHomeTab() {
mainBinding.content1.performClick()
} }
fun resetItemIcon() { fun resetItemIcon() {
@@ -170,19 +222,28 @@ class MainActivity : CKLHBaseActivity(),View.OnClickListener {
} }
fun checkUpdate(){ fun checkUpdate(){
if (hasCheckedUpdate) return
hasCheckedUpdate = true
TTHttpClient.get(this,"更新", TTRequestParam(),object : ICallback{ TTHttpClient.get(this,"更新", TTRequestParam(),object : ICallback{
override fun onSuccess(data: String) { override fun onSuccess(data: String) {
var mode = Gson().fromJson<UpdateModel>(data,UpdateModel::class.java) val model = Gson().fromJson<UpdateModel>(data, UpdateModel::class.java)
if (mode.androidVersion != TTUtils.getVersionCode(this@MainActivity)){ val currentVersionCode = TTUtils.getVersionCode(this@MainActivity)
CKUpdateAlertDialog(this@MainActivity,mode if (model.versionCode > currentVersionCode) {
.content!!,mode.isForce,object : CKUpdateAlertDialog.AlertClickListener{ val updateContent = model.content.orEmpty().replace("\\n", "\n")
updateDialog = CKUpdateAlertDialog(this@MainActivity, updateContent,
model.isForce, object : CKUpdateAlertDialog.AlertClickListener{
override fun onBack(isConfirm: Boolean) { override fun onBack(isConfirm: Boolean) {
if (isConfirm) {
if (!model.isForce) {
toast("更新下载进度可在任务栏中查看")
} }
}).show() requestUpdateDownload(model)
}
}
}).also { it.show() }
} }
} }
@@ -192,4 +253,91 @@ class MainActivity : CKLHBaseActivity(),View.OnClickListener {
} }
}) })
} }
private fun requestUpdateDownload(model: UpdateModel) {
if (model.downloadUrl.isNullOrBlank()) {
toast(getString(R.string.update_url_invalid))
return
}
pendingUpdate = model
if (!model.isForce && Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) !=
PackageManager.PERMISSION_GRANTED
) {
notificationPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
return
}
startUpdateDownload(model)
}
private fun startUpdateDownload(model: UpdateModel) {
pendingUpdate = null
if (model.isForce) {
updateDialog?.showDownloadProgress()
} else {
updateDialog?.dismiss()
updateDialog = null
}
AppUpdateDownloader(applicationContext).download(
model.downloadUrl.orEmpty(),
showNotification = !model.isForce,
callback = object : AppUpdateDownloader.Callback {
override fun onProgress(percent: Int) {
runOnUiThread { updateDialog?.updateProgress(percent) }
}
override fun onComplete(apkFile: File) {
runOnUiThread {
if (model.isForce) {
updateDialog?.dismiss()
updateDialog = null
}
pendingApk = apkFile
installApk(apkFile)
}
}
override fun onError(message: String) {
runOnUiThread {
updateDialog?.showDownloadError()
toast(getString(R.string.update_download_failed, message))
}
}
}
)
}
private fun installApk(apkFile: File) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
!packageManager.canRequestPackageInstalls()
) {
toast(getString(R.string.install_permission_required))
installPermissionLauncher.launch(
Intent(
Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES,
Uri.parse("package:$packageName")
)
)
return
}
pendingApk = null
val apkUri = FileProvider.getUriForFile(
this,
"$packageName.fileprovider",
apkFile
)
startActivity(
Intent(Intent.ACTION_VIEW).apply {
setDataAndType(apkUri, "application/vnd.android.package-archive")
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
)
}
companion object {
const val EXTRA_SHOW_HOME = "extra_show_home"
private const val EXIT_INTERVAL_MS = 2_000L
private var hasCheckedUpdate = false
}
} }

View File

@@ -8,6 +8,7 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.ck.ckcollar.app.CKApp
import com.ck.ckcollar.app.R import com.ck.ckcollar.app.R
import com.ck.ckcollar.app.databinding.FragmentHealthBinding import com.ck.ckcollar.app.databinding.FragmentHealthBinding
import com.ck.ckcollar.app.databinding.LayoutItemNoteBinding import com.ck.ckcollar.app.databinding.LayoutItemNoteBinding
@@ -16,6 +17,7 @@ import com.ck.ckcollar.app.model.CustomerStatusModel
import com.ck.ckcollar.app.model.HealthNoteModel import com.ck.ckcollar.app.model.HealthNoteModel
import com.ck.ckcollar.app.ui.act.customer.CustomerActivity import com.ck.ckcollar.app.ui.act.customer.CustomerActivity
import com.ck.ckcollar.app.ui.act.customer.PeopleCustomerActivity import com.ck.ckcollar.app.ui.act.customer.PeopleCustomerActivity
import com.ck.ckcollar.app.ui.act.login.LoginActivity
import com.ck.ckcollar.app.ui.act.note.NoteDetailsActivity import com.ck.ckcollar.app.ui.act.note.NoteDetailsActivity
import com.ck.ckcollar.app.ui.base.CKBaseFragment import com.ck.ckcollar.app.ui.base.CKBaseFragment
import com.ck.ckcollar.app.ui.dialog.CKAlertDialog import com.ck.ckcollar.app.ui.dialog.CKAlertDialog
@@ -24,9 +26,6 @@ import com.ck.ckcollar.app.utils.networkone.TTHttpClient
import com.ck.ckcollar.app.utils.networkone.model.TTRequestData import com.ck.ckcollar.app.utils.networkone.model.TTRequestData
import com.ck.ckcollar.app.utils.networkone.model.TTRequestParam import com.ck.ckcollar.app.utils.networkone.model.TTRequestParam
import com.google.gson.Gson import com.google.gson.Gson
import com.scwang.smartrefresh.layout.api.RefreshLayout
import com.scwang.smartrefresh.layout.listener.OnLoadMoreListener
import com.scwang.smartrefresh.layout.listener.OnRefreshLoadMoreListener
import com.tt.kit.base.TTBaseActivity import com.tt.kit.base.TTBaseActivity
import com.tt.kit.model.Data import com.tt.kit.model.Data
import com.tt.kit.model.DataCollection import com.tt.kit.model.DataCollection
@@ -64,26 +63,37 @@ class HealthFragment: CKBaseFragment() {
binding.recyclerView.adapter = noteAdapter binding.recyclerView.adapter = noteAdapter
binding.btnAIText.setOnClickListener { binding.btnAIText.setOnClickListener {
if (!requireLogin()) return@setOnClickListener
toActivity(CustomerActivity::class.java, DataCollection()) toActivity(CustomerActivity::class.java, DataCollection())
} }
binding.btnAIPhoto.setOnClickListener { binding.btnAIPhoto.setOnClickListener {
if (!requireLogin()) return@setOnClickListener
toActivity(CustomerActivity::class.java, DataCollection()) toActivity(CustomerActivity::class.java, DataCollection())
} }
binding.contentCustomer.setOnClickListener { binding.contentCustomer.setOnClickListener {
if (!requireLogin()) return@setOnClickListener
checkCustomerStatus() checkCustomerStatus()
} }
binding.refreshLayout.setEnableLoadMore(false) binding.refreshLayout.setEnableLoadMore(false)
binding.refreshLayout.setOnRefreshListener { binding.refreshLayout.setOnRefreshListener {
page = 1 page = 1
getData() getData()
if (CKApp.app.isUserLoggedIn) {
getCustomerTime() getCustomerTime()
} }
}
} }
private fun requireLogin(): Boolean {
if (CKApp.app.isUserLoggedIn) return true
toActivity(LoginActivity::class.java, DataCollection())
return false
}
override fun initData() { override fun initData() {
@@ -93,6 +103,7 @@ class HealthFragment: CKBaseFragment() {
fun getCustomerTime(){ fun getCustomerTime(){
if (!CKApp.app.isUserLoggedIn) return
TTHttpClient.get(activity as TTBaseActivity,"客服在线状态", TTRequestParam(),object : ICallback{ TTHttpClient.get(activity as TTBaseActivity,"客服在线状态", TTRequestParam(),object : ICallback{
override fun onSuccess(data: String) { override fun onSuccess(data: String) {
@@ -101,7 +112,19 @@ class HealthFragment: CKBaseFragment() {
binding.textDate.text = getString(R.string.pet_advisor2) binding.textDate.text = getString(R.string.pet_advisor2)
binding.textDate2.text = "("+customerStatusModel.serviceStartTime +","+customerStatusModel.serviceEndTime+")" val serviceTimes = listOfNotNull(
customerStatusModel.serviceStartTime?.takeIf { it.isNotBlank() },
customerStatusModel.serviceEndTime?.takeIf { it.isNotBlank() }
)
binding.textDate2.text = when (serviceTimes.size) {
0 -> getString(R.string.pet_advisor_time_default)
1 -> serviceTimes.first()
else -> getString(
R.string.pet_advisor_time_format,
serviceTimes[0],
serviceTimes[1]
)
}
} }
override fun onFailed(code: String, msg: String) { override fun onFailed(code: String, msg: String) {
@@ -116,6 +139,8 @@ class HealthFragment: CKBaseFragment() {
} }
fun getData(){ fun getData(){
// if (!CKApp.app.isUserLoggedIn) return
TTHttpClient.get(activity as TTBaseActivity,"宠物知识列表", TTRequestParam().apply { TTHttpClient.get(activity as TTBaseActivity,"宠物知识列表", TTRequestParam().apply {
add( add(
TTRequestData("pageNum", page) TTRequestData("pageNum", page)
@@ -144,7 +169,8 @@ class HealthFragment: CKBaseFragment() {
override fun onFailed(code: String, msg: String) { override fun onFailed(code: String, msg: String) {
try { try {
toast(msg) toast(msg)
binding.refreshLayout.finishLoadMore(true) binding.refreshLayout.finishLoadMore(false)
binding.refreshLayout.finishRefresh(false)
}catch (e : Exception){ }catch (e : Exception){
e.printStackTrace() e.printStackTrace()

View File

@@ -1,26 +1,36 @@
package com.ck.ckcollar.app.ui.act.home.fragment package com.ck.ckcollar.app.ui.act.home.fragment
import android.Manifest
import android.app.Activity.RESULT_OK import android.app.Activity.RESULT_OK
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.GradientDrawable.Orientation import android.graphics.drawable.GradientDrawable.Orientation
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Environment import android.os.Environment
import android.provider.MediaStore import android.provider.MediaStore
import android.provider.Settings
import android.text.TextUtils import android.text.TextUtils
import android.view.Gravity
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.WindowManager
import android.widget.ImageView import android.widget.ImageView
import android.widget.PopupWindow import android.widget.PopupWindow
import android.widget.TextView
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.core.app.ActivityCompat
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.load.resource.bitmap.RoundedCorners import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.RequestOptions
import com.ck.ckcollar.app.CKApp
import com.ck.ckcollar.app.R import com.ck.ckcollar.app.R
import com.ck.ckcollar.app.databinding.FragmentHomeBinding import com.ck.ckcollar.app.databinding.FragmentHomeBinding
import com.ck.ckcollar.app.listenner.OnItemClickListenner import com.ck.ckcollar.app.listenner.OnItemClickListenner
@@ -35,12 +45,14 @@ import com.ck.ckcollar.app.ui.act.petmanager.InputInviteCodeActivity
import com.ck.ckcollar.app.ui.act.petmanager.MapLocationActivity import com.ck.ckcollar.app.ui.act.petmanager.MapLocationActivity
import com.ck.ckcollar.app.ui.act.petmanager.PetManagerActivity import com.ck.ckcollar.app.ui.act.petmanager.PetManagerActivity
import com.ck.ckcollar.app.ui.act.petmanager.ViewPetFileActivity import com.ck.ckcollar.app.ui.act.petmanager.ViewPetFileActivity
import com.ck.ckcollar.app.ui.act.login.LoginActivity
import com.ck.ckcollar.app.ui.base.CKBaseFragment import com.ck.ckcollar.app.ui.base.CKBaseFragment
import com.ck.ckcollar.app.ui.dialog.CKAlertDialog import com.ck.ckcollar.app.ui.dialog.CKAlertDialog
import com.ck.ckcollar.app.ui.popview.CKCollarTypePopView import com.ck.ckcollar.app.ui.popview.CKCollarTypePopView
import com.ck.ckcollar.app.ui.popview.CKPowerAlertView import com.ck.ckcollar.app.ui.popview.CKPowerAlertView
import com.ck.ckcollar.app.utils.CKUtils import com.ck.ckcollar.app.utils.CKUtils
import com.ck.ckcollar.app.utils.Const import com.ck.ckcollar.app.utils.Const
import com.ck.ckcollar.app.utils.LubanCompressUtil
import com.ck.ckcollar.app.utils.networkone.ICallback import com.ck.ckcollar.app.utils.networkone.ICallback
import com.ck.ckcollar.app.utils.networkone.TTHttpClient import com.ck.ckcollar.app.utils.networkone.TTHttpClient
import com.ck.ckcollar.app.utils.networkone.model.TTRequestData import com.ck.ckcollar.app.utils.networkone.model.TTRequestData
@@ -67,6 +79,38 @@ import kotlin.random.Random
class HomeFragment : CKBaseFragment() { class HomeFragment : CKBaseFragment() {
private enum class CameraAction { SCAN, TAKE_PHOTO }
private var pendingCameraAction: CameraAction? = null
private var imageUploadInProgress = false
private var permissionTopDialog: AlertDialog? = null
private val cameraSettingsLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) {
val action = pendingCameraAction
pendingCameraAction = null
if (checkCameraPermissions()) {
performCameraAction(action)
}
}
private val cameraPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { granted ->
hideCameraPermissionTopDialog()
val action = pendingCameraAction
if (granted) {
pendingCameraAction = null
performCameraAction(action)
} else if (!ActivityCompat.shouldShowRequestPermissionRationale(
requireActivity(),
Manifest.permission.CAMERA
)) {
showCameraSettingsDialog()
} else {
pendingCameraAction = null
}
}
lateinit var homeBinding: FragmentHomeBinding lateinit var homeBinding: FragmentHomeBinding
var collarDatas = listOf<CollarTypeModel.TypeDataModel>() var collarDatas = listOf<CollarTypeModel.TypeDataModel>()
@@ -75,6 +119,9 @@ class HomeFragment : CKBaseFragment() {
var dataModel: CollarTypeModel.TypeDataModel? = null var dataModel: CollarTypeModel.TypeDataModel? = null
var homeModel: HomeModel? = null var homeModel: HomeModel? = null
var isFirstShow = false var isFirstShow = false
private var waitingForLoginResult = false
private var loadedLoginToken: String? = null
private var shouldRefreshPetListOnResume = false
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
@@ -99,10 +146,13 @@ class HomeFragment : CKBaseFragment() {
homeBinding.textName?.setOnClickListener { homeBinding.textName?.setOnClickListener {
getPetList() if (!requireLogin()) return@setOnClickListener
if (collarDatas.size <= 1) return@setOnClickListener
showPetSelector()
} }
//扫一扫 //扫一扫
homeBinding.btnScan?.setOnClickListener { homeBinding.btnScan?.setOnClickListener {
if (!requireLogin()) return@setOnClickListener
if (dataModel == null) { if (dataModel == null) {
toast(getString(R.string.choose_pet_alert)) toast(getString(R.string.choose_pet_alert))
return@setOnClickListener return@setOnClickListener
@@ -111,6 +161,11 @@ class HomeFragment : CKBaseFragment() {
if (!checkCameraPermissions()){ if (!checkCameraPermissions()){
CKAlertDialog(activity!!,getString(R.string.alert),getString(R.string.camera_alert),object : CKAlertDialog.AlertClickListener{ CKAlertDialog(activity!!,getString(R.string.alert),getString(R.string.camera_alert),object : CKAlertDialog.AlertClickListener{
override fun onBack(isConfirm: Boolean) { override fun onBack(isConfirm: Boolean) {
if(isConfirm){
requestCameraPermission(CameraAction.SCAN)
}else{
}
} }
}).show() }).show()
@@ -120,13 +175,14 @@ class HomeFragment : CKBaseFragment() {
startScan() startScan()
} }
homeBinding.btnCamera?.setOnClickListener { homeBinding.btnCamera?.setOnClickListener {
if (!requireLogin()) return@setOnClickListener
try { try {
if (!checkCameraPermissions()){ if (!checkCameraPermissions()){
CKAlertDialog(activity!!,getString(R.string.alert),getString(R.string.camera_alert),object : CKAlertDialog.AlertClickListener{ CKAlertDialog(activity!!,getString(R.string.alert),getString(R.string.camera_alert),object : CKAlertDialog.AlertClickListener{
override fun onBack(isConfirm: Boolean) { override fun onBack(isConfirm: Boolean) {
if (isConfirm) requestCameraPermission(CameraAction.TAKE_PHOTO)
} }
}).show() }).show()
return@setOnClickListener return@setOnClickListener
@@ -139,9 +195,11 @@ class HomeFragment : CKBaseFragment() {
} }
} }
homeBinding.btnManager?.setOnClickListener { homeBinding.btnManager?.setOnClickListener {
if (!requireLogin()) return@setOnClickListener
toActivity(PetManagerActivity::class.java, DataCollection()) toActivity(PetManagerActivity::class.java, DataCollection())
} }
homeBinding.btnAddPet?.setOnClickListener { homeBinding.btnAddPet?.setOnClickListener {
if (!requireLogin()) return@setOnClickListener
toActivity(AddPetActivity::class.java, DataCollection()) toActivity(AddPetActivity::class.java, DataCollection())
} }
@@ -167,6 +225,11 @@ class HomeFragment : CKBaseFragment() {
} }
homeBinding.btnViewPostion?.setOnClickListener { homeBinding.btnViewPostion?.setOnClickListener {
if (!requireLogin()) return@setOnClickListener
if(homeModel?.equipment?.collNum == null){
toast("请为您的爱宠绑定项圈")
return@setOnClickListener
}
getData(dataModel?.id.toString()) getData(dataModel?.id.toString())
// toActivity(MapLocationActivity::class.java, DataCollection().apply { // toActivity(MapLocationActivity::class.java, DataCollection().apply {
@@ -185,6 +248,10 @@ class HomeFragment : CKBaseFragment() {
}) })
} }
homeBinding.refreshLayout?.setOnRefreshListener { homeBinding.refreshLayout?.setOnRefreshListener {
if (!CKApp.app.isUserLoggedIn) {
homeBinding.refreshLayout?.finishRefresh()
return@setOnRefreshListener
}
if (dataModel == null) { if (dataModel == null) {
getData("") getData("")
@@ -199,10 +266,75 @@ class HomeFragment : CKBaseFragment() {
homeBinding.btnTraining?.setOnClickListener { homeBinding.btnTraining?.setOnClickListener {
toast(getString(R.string.waitting_open_area)) toast(getString(R.string.waitting_open_area))
} }
LiveDataBus.get().with("FIRST", Int::class.java)
.observe(viewLifecycleOwner, object : Observer<Int?> {
override fun onChanged(result: Int?) {
shouldRefreshPetListOnResume = true
}
})
}
private fun requireLogin(): Boolean {
if (CKApp.app.isUserLoggedIn) return true
waitingForLoginResult = true
toActivity(LoginActivity::class.java, DataCollection())
return false
}
private fun requestCameraPermission(action: CameraAction) {
pendingCameraAction = action
showCameraPermissionTopDialog()
permissionTopDialog?.window?.decorView?.post {
if (isAdded && pendingCameraAction == action) {
cameraPermissionLauncher.launch(Manifest.permission.CAMERA)
}
}
}
private fun showCameraPermissionTopDialog() {
permissionTopDialog?.dismiss()
val view = layoutInflater.inflate(R.layout.permission_top_dialog, null)
view.findViewById<TextView>(R.id.permissionTopTitle).text = getString(R.string.camera)
view.findViewById<TextView>(R.id.permissionTopContent).text = getString(R.string.camera_alert)
permissionTopDialog = AlertDialog.Builder(requireContext())
.setView(view)
.create()
.also { dialog ->
dialog.setCanceledOnTouchOutside(false)
dialog.setCancelable(false)
dialog.show()
dialog.window?.apply {
setBackgroundDrawable(ColorDrawable(android.graphics.Color.TRANSPARENT))
setGravity(Gravity.TOP)
setLayout(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT
)
}
}
}
private fun hideCameraPermissionTopDialog() {
permissionTopDialog?.dismiss()
permissionTopDialog = null
}
override fun onDestroyView() {
hideCameraPermissionTopDialog()
pendingCameraAction = null
super.onDestroyView()
} }
override fun initData() { override fun initData() {
if (!CKApp.app.isUserLoggedIn) {
resetLoggedOutState()
return
}
loadedLoginToken = CKApp.app.token
var data = PreferencesUtils.getString(activity!!, Const.PET_DATA, "") var data = PreferencesUtils.getString(activity!!, Const.PET_DATA, "")
if (!TextUtils.isEmpty(data)) { if (!TextUtils.isEmpty(data)) {
@@ -222,18 +354,9 @@ class HomeFragment : CKBaseFragment() {
} }
if (isFirstShow) {
getPetList() getPetList()
}
LiveDataBus.get().with("FIRST", Int::class.java)
.observe(viewLifecycleOwner, object : Observer<Int?> {
override fun onChanged(result: Int?) {
getPetList2()
}
})
} }
fun takePhoto() { fun takePhoto() {
@@ -275,22 +398,15 @@ class HomeFragment : CKBaseFragment() {
} }
fun getData(id: String) { fun getData(id: String) {
if (!CKApp.app.isUserLoggedIn) return
TTHttpClient.get(activity as TTBaseActivity, "首页", TTRequestParam().apply { TTHttpClient.get(activity as TTBaseActivity, "首页", TTRequestParam().apply {
add(TTRequestData("patId", id)) add(TTRequestData("patId", id))
}, object : ICallback { }, object : ICallback {
override fun onSuccess(data: String) { override fun onSuccess(data: String) {
if (!CKApp.app.isUserLoggedIn) return
homeModel = Gson().fromJson<HomeModel>(data, HomeModel::class.java) homeModel = Gson().fromJson<HomeModel>(data, HomeModel::class.java)
bannarData = homeModel?.banners!! setBannerData(homeModel?.banners.orEmpty())
imageAdapter = ImageAdapter(activity!!, bannarData, object : OnItemClickListenner {
override fun onClick(pos: Int, model: Any) {
}
})
homeBinding.banner.addBannerLifecycleObserver(this@HomeFragment)//添加生命周期观察者
.setAdapter(imageAdapter)
.setIndicator(CircleIndicator(activity));
} }
@@ -299,9 +415,9 @@ class HomeFragment : CKBaseFragment() {
} }
}) })
TTHttpClient.get(activity as TTBaseActivity, "设备信息", TTRequestParam().apply { add(TTRequestData("patId",id)) },object : ICallback{ TTHttpClient.get(activity as TTBaseActivity, "设备信息", TTRequestParam().apply { add(TTRequestData("patId",id)) },object : ICallback{
override fun onSuccess(data: String) { override fun onSuccess(data: String) {
if (!CKApp.app.isUserLoggedIn) return
var model = Gson().fromJson<HomeModel.EquipmentModel>(data, HomeModel.EquipmentModel::class.java) var model = Gson().fromJson<HomeModel.EquipmentModel>(data, HomeModel.EquipmentModel::class.java)
homeModel?.equipment = model homeModel?.equipment = model
@@ -395,7 +511,53 @@ class HomeFragment : CKBaseFragment() {
}) })
} }
private fun performCameraAction(action: CameraAction?) {
when (action) {
CameraAction.SCAN -> startScan()
CameraAction.TAKE_PHOTO -> takePhoto()
null -> Unit
}
}
private fun showCameraSettingsDialog() {
CKAlertDialog(
requireActivity(),
getString(R.string.settting_permissions),
getString(R.string.camera_permission_settings_alert),
object : CKAlertDialog.AlertClickListener {
override fun onBack(isConfirm: Boolean) {
if (isConfirm) {
val intent = Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.parse("package:${requireContext().packageName}")
)
cameraSettingsLauncher.launch(intent)
} else {
pendingCameraAction = null
}
}
}
).show()
}
private fun setBannerData(data: List<BannarModel>) {
bannarData = data
if (::imageAdapter.isInitialized) {
imageAdapter.mDatas = bannarData
homeBinding.banner.setDatas(bannarData)
return
}
imageAdapter = ImageAdapter(activity!!, bannarData, object : OnItemClickListenner {
override fun onClick(pos: Int, model: Any) = Unit
})
homeBinding.banner.addBannerLifecycleObserver(this@HomeFragment)
.setAdapter(imageAdapter)
.setIndicator(CircleIndicator(activity))
}
fun switchPet() { fun switchPet() {
if (!CKApp.app.isUserLoggedIn) return
LiveDataBus.get().with("BOUND" + dataModel!!.id, Int::class.java) LiveDataBus.get().with("BOUND" + dataModel!!.id, Int::class.java)
@@ -431,6 +593,7 @@ class HomeFragment : CKBaseFragment() {
} }
fun getPetInfo(id: String) { fun getPetInfo(id: String) {
if (!CKApp.app.isUserLoggedIn) return
TTHttpClient.get(activity as TTBaseActivity, "宠物档案", id, object : ICallback { TTHttpClient.get(activity as TTBaseActivity, "宠物档案", id, object : ICallback {
override fun onSuccess(data: String) { override fun onSuccess(data: String) {
var model = Gson().fromJson<CollarTypeModel.TypeDataModel>( var model = Gson().fromJson<CollarTypeModel.TypeDataModel>(
@@ -517,6 +680,7 @@ class HomeFragment : CKBaseFragment() {
fun getPetList() { fun getPetList() {
if (!CKApp.app.isUserLoggedIn) return
showProgeassDialog(getString(R.string.search)) showProgeassDialog(getString(R.string.search))
TTHttpClient.get(activity as TTBaseActivity, "宠物列表", TTRequestParam().apply { TTHttpClient.get(activity as TTBaseActivity, "宠物列表", TTRequestParam().apply {
add( add(
@@ -529,11 +693,45 @@ class HomeFragment : CKBaseFragment() {
override fun onSuccess(data: String) { override fun onSuccess(data: String) {
hiddenProgeassDialog() hiddenProgeassDialog()
if (!CKApp.app.isUserLoggedIn) return
var model = Gson().fromJson<CollarTypeModel>(data, CollarTypeModel::class.java) var model = Gson().fromJson<CollarTypeModel>(data, CollarTypeModel::class.java)
if (!isFirstShow) {
collarDatas = model.rows collarDatas = model.rows
if (model.rows.isEmpty()) {
isFirstShow = false
dataModel = null
homeBinding.textName?.text = getString(R.string.choost_pet)
PreferencesUtils.putString(activity!!, Const.PET_DATA, "")
return
}
if (isFirstShow) {
isFirstShow = false
dataModel = model.rows.first()
homeBinding.textName?.text = dataModel?.patName
switchPet()
} else {
val currentPet = model.rows.firstOrNull { it.id == dataModel?.id }
if (currentPet != null) {
dataModel = currentPet
homeBinding.textName?.text = currentPet.patName
} else if (model.rows.isNotEmpty()) {
dataModel = model.rows.first()
homeBinding.textName?.text = dataModel?.patName
switchPet()
}
}
}
override fun onFailed(code: String, msg: String) {
hiddenProgeassDialog()
toast(msg)
}
})
}
private fun showPetSelector() {
homeBinding.btnRotate?.rotateDownward() homeBinding.btnRotate?.rotateDownward()
CKCollarTypePopView( CKCollarTypePopView(
activity!!, activity!!,
@@ -549,38 +747,20 @@ class HomeFragment : CKBaseFragment() {
model: CollarTypeModel.TypeDataModel model: CollarTypeModel.TypeDataModel
) { ) {
dataModel = model dataModel = model
homeBinding.textName?.setText(model.patName) homeBinding.textName?.text = model.patName
switchPet() switchPet()
dataModel?.let {
PreferencesUtils.putString( PreferencesUtils.putString(
activity!!, activity!!,
Const.PET_DATA, Const.PET_DATA,
Gson().toJson(dataModel) Gson().toJson(dataModel)
) )
} }
}
})
} else {
isFirstShow = false
if (model.rows.size > 0) {
dataModel = model.rows.get(0)
homeBinding.textName?.setText(dataModel?.patName)
switchPet()
}
}
}
override fun onFailed(code: String, msg: String) {
hiddenProgeassDialog()
toast(msg)
}
}) })
} }
fun getPetList2() { fun getPetList2() {
if (!CKApp.app.isUserLoggedIn) return
showProgeassDialog(getString(R.string.search)) showProgeassDialog(getString(R.string.search))
TTHttpClient.get(activity as TTBaseActivity, "宠物列表", TTRequestParam().apply { TTHttpClient.get(activity as TTBaseActivity, "宠物列表", TTRequestParam().apply {
add( add(
@@ -593,6 +773,7 @@ class HomeFragment : CKBaseFragment() {
override fun onSuccess(data: String) { override fun onSuccess(data: String) {
hiddenProgeassDialog() hiddenProgeassDialog()
if (!CKApp.app.isUserLoggedIn) return
var model = Gson().fromJson<CollarTypeModel>(data, CollarTypeModel::class.java) var model = Gson().fromJson<CollarTypeModel>(data, CollarTypeModel::class.java)
if (model.rows.size == 1) { if (model.rows.size == 1) {
@@ -615,12 +796,31 @@ class HomeFragment : CKBaseFragment() {
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 55 && resultCode == RESULT_OK) { if (requestCode == 55 && resultCode == RESULT_OK) {
var path = PreferencesUtils.getString(activity!!, Const.IMAGE_PATH, "") val path = PreferencesUtils.getString(activity!!, Const.IMAGE_PATH, "")
uploadImage(path!!) if (!path.isNullOrBlank()) {
imageUploadInProgress = true
LubanCompressUtil.getCompressFile(
requireContext(),
File(path),
object : LubanCompressUtil.CompressCallback {
override fun success(file: File) {
if (!isAdded) return
uploadImage(file.absolutePath)
}
override fun fail(failMsg: String) {
if (!isAdded) return
imageUploadInProgress = false
toast(failMsg)
}
}
)
}
} }
} }
fun uploadImage(path: String) { fun uploadImage(path: String) {
if (!CKApp.app.isUserLoggedIn) return
var param = TTRequestParam() var param = TTRequestParam()
param.files.add(File(path)) param.files.add(File(path))
@@ -628,6 +828,11 @@ class HomeFragment : CKBaseFragment() {
showProgeassDialog(getString(R.string.see)) showProgeassDialog(getString(R.string.see))
TTHttpClient.postFile(activity as TTBaseActivity, "上传照片s", param, object : ICallback { TTHttpClient.postFile(activity as TTBaseActivity, "上传照片s", param, object : ICallback {
override fun onSuccess(data: String) { override fun onSuccess(data: String) {
if (!CKApp.app.isUserLoggedIn) {
imageUploadInProgress = false
hiddenProgeassDialog()
return
}
var model = Gson().fromJson<UploadModel>(data, UploadModel::class.java) var model = Gson().fromJson<UploadModel>(data, UploadModel::class.java)
//aiPhoto(ActionCode.BASE_URL + "/" + model.fileNames) //aiPhoto(ActionCode.BASE_URL + "/" + model.fileNames)
@@ -635,6 +840,7 @@ class HomeFragment : CKBaseFragment() {
} }
override fun onFailed(code: String, msg: String) { override fun onFailed(code: String, msg: String) {
imageUploadInProgress = false
hiddenProgeassDialog() hiddenProgeassDialog()
toast(msg) toast(msg)
} }
@@ -642,12 +848,15 @@ class HomeFragment : CKBaseFragment() {
} }
fun aiPhoto(imageUrl: String) { fun aiPhoto(imageUrl: String) {
if (!CKApp.app.isUserLoggedIn) return
TTHttpClient.postJson(activity as TTBaseActivity, "AI拍照识别", TTRequestParam().apply { TTHttpClient.postJson(activity as TTBaseActivity, "AI拍照识别", TTRequestParam().apply {
add(TTRequestData("imageUrl", imageUrl)) add(TTRequestData("imageUrl", imageUrl))
}, object : ICallback { }, object : ICallback {
override fun onSuccess(data: String) { override fun onSuccess(data: String) {
imageUploadInProgress = false
hiddenProgeassDialog() hiddenProgeassDialog()
if (!CKApp.app.isUserLoggedIn) return
var model = Gson().fromJson<AIPhotoModel>(data, AIPhotoModel::class.java) var model = Gson().fromJson<AIPhotoModel>(data, AIPhotoModel::class.java)
if ("".equals(model.species) || "".equals(model.species)) { if ("".equals(model.species) || "".equals(model.species)) {
@@ -665,6 +874,7 @@ class HomeFragment : CKBaseFragment() {
} }
override fun onFailed(code: String, msg: String) { override fun onFailed(code: String, msg: String) {
imageUploadInProgress = false
hiddenProgeassDialog() hiddenProgeassDialog()
toast(msg) toast(msg)
} }
@@ -705,11 +915,62 @@ class HomeFragment : CKBaseFragment() {
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
homeBinding.banner.start(); homeBinding.banner.start();
if (!CKApp.app.isUserLoggedIn) {
waitingForLoginResult = false
resetLoggedOutState()
return
}
if (waitingForLoginResult) {
waitingForLoginResult = false
if (CKApp.app.isUserLoggedIn) {
getPetList()
}
}
dataModel?.let { dataModel?.let {
getData(dataModel!!.id.toString()) getData(dataModel!!.id.toString())
} }
} }
override fun onResume() {
super.onResume()
if (CKApp.app.isUserLoggedIn && loadedLoginToken != CKApp.app.token) {
initData()
} else if (CKApp.app.isUserLoggedIn && shouldRefreshPetListOnResume && !imageUploadInProgress) {
getPetList()
}
shouldRefreshPetListOnResume = false
}
override fun onPause() {
super.onPause()
shouldRefreshPetListOnResume = true
}
private fun resetLoggedOutState() {
loadedLoginToken = null
collarDatas = emptyList()
bannarData = emptyList()
dataModel = null
homeModel = null
isFirstShow = false
homeBinding.textName?.text = getString(R.string.choost_pet)
homeBinding.btnBound?.text = getString(R.string.unbound)
homeBinding.textHealthPoints?.text = "--"
homeBinding.points?.visibility = View.GONE
homeBinding.textStep?.text = "-"
homeBinding.textAddress?.text = getString(R.string.no_position)
homeBinding.textDistance?.text = "-"
homeBinding.textPowerValue?.text = "%"
homeBinding.imagePower?.setImageResource(R.mipmap.image_power_0)
homeBinding.contentPower?.visibility = View.GONE
setNoDeviceUI()
setBannerData(listOf(BannarModel().apply {
localImageRes = R.mipmap.index_banner1
}))
homeBinding.refreshLayout?.finishRefresh()
}
override fun onStop() { override fun onStop() {
super.onStop() super.onStop()
homeBinding.banner.stop(); homeBinding.banner.stop();
@@ -749,8 +1010,11 @@ class HomeFragment : CKBaseFragment() {
position: Int, position: Int,
size: Int size: Int
) { ) {
val imageSource: Any? = data?.localImageRes
?.takeIf { it != 0 }
?: data?.bannerUrl
Glide.with(context) Glide.with(context)
.load(data?.bannerUrl) .load(imageSource)
.apply(RequestOptions.bitmapTransform(RoundedCorners(12))) .apply(RequestOptions.bitmapTransform(RoundedCorners(12)))
.placeholder(R.mipmap.image_bannar_item) .placeholder(R.mipmap.image_bannar_item)
.into(holder!!.imageView) .into(holder!!.imageView)

View File

@@ -17,6 +17,7 @@ import com.ck.ckcollar.app.ui.act.deposit.DepositActivity
import com.ck.ckcollar.app.ui.act.deposit.StartDepositActivity import com.ck.ckcollar.app.ui.act.deposit.StartDepositActivity
import com.ck.ckcollar.app.ui.act.member.MemberActivity import com.ck.ckcollar.app.ui.act.member.MemberActivity
import com.ck.ckcollar.app.ui.act.message.MessageCenterActivity import com.ck.ckcollar.app.ui.act.message.MessageCenterActivity
import com.ck.ckcollar.app.ui.act.login.LoginActivity
import com.ck.ckcollar.app.ui.act.mine.FeedBackActivity import com.ck.ckcollar.app.ui.act.mine.FeedBackActivity
import com.ck.ckcollar.app.ui.act.mine.ReturnDeviceActivity import com.ck.ckcollar.app.ui.act.mine.ReturnDeviceActivity
import com.ck.ckcollar.app.ui.act.points.PointsActivity import com.ck.ckcollar.app.ui.act.points.PointsActivity
@@ -51,19 +52,24 @@ class MineFragment : CKBaseFragment() {
override fun initView() { override fun initView() {
binding.contentBalance.setOnClickListener { binding.contentBalance.setOnClickListener {
if (!requireLogin()) return@setOnClickListener
toActivity(BalanceActivity::class.java, DataCollection()) toActivity(BalanceActivity::class.java, DataCollection())
} }
binding.conetntPoints.setOnClickListener { binding.conetntPoints.setOnClickListener {
if (!requireLogin()) return@setOnClickListener
toActivity(PointsActivity::class.java, DataCollection()) toActivity(PointsActivity::class.java, DataCollection())
} }
binding.imageUser.setOnClickListener { binding.imageUser.setOnClickListener {
if (!requireLogin()) return@setOnClickListener
toActivity(UserInfoActivity::class.java, DataCollection()) toActivity(UserInfoActivity::class.java, DataCollection())
} }
binding.btnUserInfo.setOnClickListener { binding.btnUserInfo.setOnClickListener {
if (!requireLogin()) return@setOnClickListener
toActivity(UserInfoActivity::class.java, DataCollection()) toActivity(UserInfoActivity::class.java, DataCollection())
} }
binding.btnMessage.setOnClickListener { binding.btnMessage.setOnClickListener {
if (!requireLogin()) return@setOnClickListener
toActivity(MessageCenterActivity::class.java, DataCollection()) toActivity(MessageCenterActivity::class.java, DataCollection())
} }
@@ -71,19 +77,24 @@ class MineFragment : CKBaseFragment() {
toActivity(SettingActivity::class.java, DataCollection()) toActivity(SettingActivity::class.java, DataCollection())
} }
binding.btnOpen.setOnClickListener { binding.btnOpen.setOnClickListener {
if (!requireLogin()) return@setOnClickListener
toActivity(MemberActivity::class.java, DataCollection()) toActivity(MemberActivity::class.java, DataCollection())
} }
binding.btnReturnDevice.setOnClickListener { binding.btnReturnDevice.setOnClickListener {
if (!requireLogin()) return@setOnClickListener
toActivity(ReturnDeviceActivity::class.java, DataCollection()) toActivity(ReturnDeviceActivity::class.java, DataCollection())
} }
binding.btnFeedback.setOnClickListener { binding.btnFeedback.setOnClickListener {
if (!requireLogin()) return@setOnClickListener
toActivity(FeedBackActivity::class.java, DataCollection()) toActivity(FeedBackActivity::class.java, DataCollection())
} }
binding.btnCustomerService.setOnClickListener { binding.btnCustomerService.setOnClickListener {
if (!requireLogin()) return@setOnClickListener
toActivity(PeopleCustomerActivity::class.java, DataCollection().apply { add(Data("chatType","2")) }) toActivity(PeopleCustomerActivity::class.java, DataCollection().apply { add(Data("chatType","2")) })
} }
binding.textDeposit.setOnClickListener { binding.textDeposit.setOnClickListener {
if (!requireLogin()) return@setOnClickListener
if ("0".equals(CKApp.app.userInfo!!.depositStatus)){ if ("0".equals(CKApp.app.userInfo!!.depositStatus)){
toActivity(DepositActivity::class.java, DataCollection()) toActivity(DepositActivity::class.java, DataCollection())
}else{ }else{
@@ -92,18 +103,23 @@ class MineFragment : CKBaseFragment() {
} }
binding.btnAllOrder.setOnClickListener { binding.btnAllOrder.setOnClickListener {
if (!requireLogin()) return@setOnClickListener
toActivity(MyOrderActivity::class.java, DataCollection().apply { add(Data("pos","0")) }) toActivity(MyOrderActivity::class.java, DataCollection().apply { add(Data("pos","0")) })
} }
binding.btnOrderPayment.setOnClickListener { binding.btnOrderPayment.setOnClickListener {
if (!requireLogin()) return@setOnClickListener
toActivity(MyOrderActivity::class.java, DataCollection().apply { add(Data("pos","1")) }) toActivity(MyOrderActivity::class.java, DataCollection().apply { add(Data("pos","1")) })
} }
binding.btnOrderDelivery.setOnClickListener { binding.btnOrderDelivery.setOnClickListener {
if (!requireLogin()) return@setOnClickListener
toActivity(MyOrderActivity::class.java, DataCollection().apply { add(Data("pos","2")) }) toActivity(MyOrderActivity::class.java, DataCollection().apply { add(Data("pos","2")) })
} }
binding.btnOrderReceipt.setOnClickListener { binding.btnOrderReceipt.setOnClickListener {
if (!requireLogin()) return@setOnClickListener
toActivity(MyOrderActivity::class.java, DataCollection().apply { add(Data("pos","3")) }) toActivity(MyOrderActivity::class.java, DataCollection().apply { add(Data("pos","3")) })
} }
binding.btnOrderAfterSales.setOnClickListener { binding.btnOrderAfterSales.setOnClickListener {
if (!requireLogin()) return@setOnClickListener
toActivity(MyOrderActivity::class.java, DataCollection().apply { add(Data("pos","4")) }) toActivity(MyOrderActivity::class.java, DataCollection().apply { add(Data("pos","4")) })
} }
@@ -111,20 +127,39 @@ class MineFragment : CKBaseFragment() {
} }
private fun requireLogin(): Boolean {
if (CKApp.app.isUserLoggedIn) return true
toActivity(LoginActivity::class.java, DataCollection())
return false
}
override fun initData() { override fun initData() {
if (!CKApp.app.isUserLoggedIn) {
renderLoggedOutState()
binding.textNick.text = getString(R.string.guest)
binding.textPhone.text = "用户未登录"
binding.textPhone.visibility = View.VISIBLE
binding.textBalance.text = "0"
binding.textPoints.text = "0"
binding.textCount.visibility = View.INVISIBLE
binding.imageUser.setImageResource(R.mipmap.icon_unlogin_defaul)
return
}
binding.textNick.text = CKApp.app.userInfo?.custName binding.textNick.text = CKApp.app.userInfo?.custName
binding.textPhone.text = CKApp.app.userInfo?.phonenumber binding.textPhone.text = CKApp.app.userInfo?.phonenumber
binding.textPhone.visibility = View.VISIBLE
if (!TextUtils.isEmpty(CKApp.app.userInfo?.avatar)){ if (!TextUtils.isEmpty(CKApp.app.userInfo?.avatar)){
Glide.with(this@MineFragment) Glide.with(this@MineFragment)
.load( CKApp.app.userInfo?.avatar) .load( CKApp.app.userInfo?.avatar)
.placeholder(R.mipmap.image_user_default) .placeholder(R.mipmap.icon_unlogin_defaul)
.into(binding.imageUser) .into(binding.imageUser)
} }
binding.textBalance.text = CKApp.app.userInfo?.balance.toString() binding.textBalance.text = CKApp.app.userInfo?.balance?.toString() ?: "0"
binding.textPoints.text = CKApp.app.userInfo?.points.toString() binding.textPoints.text = CKApp.app.userInfo?.points?.toString() ?: "0"
if (CKApp.app.userInfo?.isMember == true){ if (CKApp.app.userInfo?.isMember == true){
binding.btnOpen.setText(getString(R.string.auto_renewal2)) binding.btnOpen.setText(getString(R.string.auto_renewal2))
@@ -135,6 +170,7 @@ class MineFragment : CKBaseFragment() {
}else{ }else{
binding.btnOpen.setText(getString(R.string.open_member)) binding.btnOpen.setText(getString(R.string.open_member))
binding.textMemberTitle.text = getString(R.string.pet_member) binding.textMemberTitle.text = getString(R.string.pet_member)
binding.textMemberDate.text = getString(R.string.pet_member_rewards)
} }
@@ -147,11 +183,36 @@ class MineFragment : CKBaseFragment() {
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
initData()
if (CKApp.app.isUserLoggedIn) {
getUserInfo() getUserInfo()
} }
fun getUserInfo(){ }
private fun renderLoggedOutState() {
binding.textNick.text = getString(R.string.guest)
binding.textPhone.text = getString(R.string.user_not_logged_in)
binding.textPhone.visibility = View.VISIBLE
binding.textBalance.text = "0"
binding.textPoints.text = "0"
binding.textCount.text = "0"
binding.textCount.visibility = View.INVISIBLE
binding.btnOpen.text = getString(R.string.open_member)
binding.textMemberTitle.text = getString(R.string.pet_member)
binding.textMemberDate.text = getString(R.string.pet_member_rewards)
Glide.with(this).clear(binding.imageUser)
binding.imageUser.setImageResource(R.mipmap.icon_unlogin_defaul)
}
private fun getUserInfo(){
if (!CKApp.app.isUserLoggedIn) {
binding.textCount.visibility = View.INVISIBLE
return
}
TTHttpClient.get(activity as TTBaseActivity,"个人资料", TTRequestParam(),object : ICallback{ TTHttpClient.get(activity as TTBaseActivity,"个人资料", TTRequestParam(),object : ICallback{
override fun onSuccess(data: String) { override fun onSuccess(data: String) {
if (!CKApp.app.isUserLoggedIn) return
CKApp.app.userInfo = Gson().fromJson<UserInfoModel>(data, UserInfoModel::class.java) CKApp.app.userInfo = Gson().fromJson<UserInfoModel>(data, UserInfoModel::class.java)
PreferencesUtils.putString(activity!!, Const.USER_DATA,data) PreferencesUtils.putString(activity!!, Const.USER_DATA,data)
@@ -168,6 +229,7 @@ class MineFragment : CKBaseFragment() {
add(TTRequestData("accept","true")) add(TTRequestData("accept","true"))
},object : ICallback{ },object : ICallback{
override fun onSuccess(data: String) { override fun onSuccess(data: String) {
if (!CKApp.app.isUserLoggedIn) return
var model = Gson().fromJson<UnReadModel>(data, UnReadModel::class.java) var model = Gson().fromJson<UnReadModel>(data, UnReadModel::class.java)
binding.textCount.text = model.unreadCount.toString() binding.textCount.text = model.unreadCount.toString()

View File

@@ -15,6 +15,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.load.resource.bitmap.RoundedCorners import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.RequestOptions
import com.ck.ckcollar.app.CKApp
import com.ck.ckcollar.app.R import com.ck.ckcollar.app.R
import com.ck.ckcollar.app.action.ActionCode import com.ck.ckcollar.app.action.ActionCode
import com.ck.ckcollar.app.databinding.FragmentShopBinding import com.ck.ckcollar.app.databinding.FragmentShopBinding
@@ -134,10 +135,12 @@ class ShopFragment : CKBaseFragment() {
} }
binding.btnShopCar.setOnClickListener { binding.btnShopCar.setOnClickListener {
if (!isUserLogin()) return@setOnClickListener
toActivity(ShopCarActivity::class.java, DataCollection()) toActivity(ShopCarActivity::class.java, DataCollection())
} }
binding.btnShopOrder.setOnClickListener { binding.btnShopOrder.setOnClickListener {
if (!isUserLogin()) return@setOnClickListener
toActivity(MyOrderActivity::class.java, DataCollection().apply { add(Data("pos","0")) }) toActivity(MyOrderActivity::class.java, DataCollection().apply { add(Data("pos","0")) })
} }
@@ -154,7 +157,7 @@ class ShopFragment : CKBaseFragment() {
getHot() getHot()
page = 1 page = 1
getData() getData()
getBannar() // getBannar()
} }
override fun onLoadMore(refreshLayout: RefreshLayout) { override fun onLoadMore(refreshLayout: RefreshLayout) {
@@ -299,6 +302,11 @@ class ShopFragment : CKBaseFragment() {
} }
fun getCarCount() { fun getCarCount() {
if (!CKApp.app.isUserLoggedIn) {
binding.textCount.visibility = View.GONE
return
}
TTHttpClient.get( TTHttpClient.get(
activity as TTBaseActivity, activity as TTBaseActivity,
"购物车数量和合计", "购物车数量和合计",

View File

@@ -91,11 +91,7 @@ class BoundPhoneActivity : CKBaseActivity() {
override fun onSuccess(data: String) { override fun onSuccess(data: String) {
var token = JSONObject(data).getString("token") var token = JSONObject(data).getString("token")
PreferencesUtils.putString( CKApp.app.setLoginToken(token)
this@BoundPhoneActivity,
Const.TOKEN, token
)
CKApp.app.token = token

View File

@@ -12,10 +12,12 @@ import android.text.style.ClickableSpan
import android.view.View import android.view.View
import com.ck.ckcollar.app.CKApp import com.ck.ckcollar.app.CKApp
import com.ck.ckcollar.app.R import com.ck.ckcollar.app.R
import com.ck.ckcollar.app.config.Config
import com.ck.ckcollar.app.databinding.ActivityLoginBinding import com.ck.ckcollar.app.databinding.ActivityLoginBinding
import com.ck.ckcollar.app.model.LoginModel import com.ck.ckcollar.app.model.LoginModel
import com.ck.ckcollar.app.model.UserInfoModel import com.ck.ckcollar.app.model.UserInfoModel
import com.ck.ckcollar.app.ui.act.home.MainActivity import com.ck.ckcollar.app.ui.act.home.MainActivity
import com.ck.ckcollar.app.ui.act.setting.SettingWebViewActivity
import com.ck.ckcollar.app.ui.base.CKBaseActivity import com.ck.ckcollar.app.ui.base.CKBaseActivity
import com.ck.ckcollar.app.utils.Const import com.ck.ckcollar.app.utils.Const
import com.ck.ckcollar.app.utils.networkone.ICallback import com.ck.ckcollar.app.utils.networkone.ICallback
@@ -32,7 +34,7 @@ import com.tt.kit.model.DataCollection
import com.tt.kit.utils.TTUtils import com.tt.kit.utils.TTUtils
/** /**
* 登录 * 登录..
*/ */
class LoginActivity : CKBaseActivity() { class LoginActivity : CKBaseActivity() {
@@ -51,7 +53,7 @@ class LoginActivity : CKBaseActivity() {
// api = WXAPIFactory.createWXAPI(this, Const.WX_APP_ID, false); // api = WXAPIFactory.createWXAPI(this, Const.WX_APP_ID, false);
setStatusBarColor(R.attr.mainBackground) setStatusBarColor(R.attr.mainBackground)
//检测权限 //检测权限
checkAppPermissions() // checkAppPermissions()
} }
@@ -67,6 +69,9 @@ class LoginActivity : CKBaseActivity() {
binding.btnLogin.setOnClickListener { binding.btnLogin.setOnClickListener {
login() login()
} }
binding.btnQuickLogin.setOnClickListener {
quickLogin()
}
binding.btnCodeLogin.setOnClickListener { binding.btnCodeLogin.setOnClickListener {
binding.btnCodeLogin.setTextColor(getColor2(R.attr.appTextColor)) binding.btnCodeLogin.setTextColor(getColor2(R.attr.appTextColor))
@@ -124,8 +129,11 @@ class LoginActivity : CKBaseActivity() {
var clickableSpan2 = object : ClickableSpan() { var clickableSpan2 = object : ClickableSpan() {
override fun onClick(v: View) { override fun onClick(v: View) {
toActivity( toActivity(
AgreementActivity::class.java, SettingWebViewActivity::class.java,
DataCollection().apply { add(Data("title", "隐私政策")) }) DataCollection().apply {
add(Data("url", Config.PRIVACY_POLICY))
add(Data("title", getString(R.string.privacy_agreement)))
})
} }
override fun updateDrawState(ds: TextPaint) { override fun updateDrawState(ds: TextPaint) {
@@ -146,7 +154,6 @@ class LoginActivity : CKBaseActivity() {
binding.btnCheck.setOnClickListener { binding.btnCheck.setOnClickListener {
isCheck = !isCheck isCheck = !isCheck
setCheckUI() setCheckUI()
PreferencesUtils.putBoolean(this@LoginActivity, Const.AGREEMENT_CHECK, isCheck)
} }
binding.btnSendCode.setOnClickListener { binding.btnSendCode.setOnClickListener {
@@ -154,6 +161,10 @@ class LoginActivity : CKBaseActivity() {
sendCode() sendCode()
} }
binding.btnWX.setOnClickListener { binding.btnWX.setOnClickListener {
if (!isCheck) {
toast(getString(R.string.alert_agreement))
return@setOnClickListener
}
val req = SendAuth.Req() val req = SendAuth.Req()
req.scope = "snsapi_userinfo" // 只能填 snsapi_userinfo req.scope = "snsapi_userinfo" // 只能填 snsapi_userinfo
req.state = "wechat_sdk_demo_test" req.state = "wechat_sdk_demo_test"
@@ -232,11 +243,7 @@ class LoginActivity : CKBaseActivity() {
try { try {
var model = Gson().fromJson<LoginModel>(data, LoginModel::class.java) var model = Gson().fromJson<LoginModel>(data, LoginModel::class.java)
PreferencesUtils.putString( CKApp.app.setLoginToken(model.token.orEmpty())
this@LoginActivity,
Const.TOKEN, model.token.toString()
)
CKApp.app.token = model.token.toString()
getUserInfo() getUserInfo()
} catch (e: Exception) { } catch (e: Exception) {
@@ -262,11 +269,7 @@ class LoginActivity : CKBaseActivity() {
try { try {
var model = Gson().fromJson<LoginModel>(data, LoginModel::class.java) var model = Gson().fromJson<LoginModel>(data, LoginModel::class.java)
PreferencesUtils.putString( CKApp.app.setLoginToken(model.token.orEmpty())
this@LoginActivity,
Const.TOKEN, model.token.toString()
)
CKApp.app.token = model.token.toString()
getUserInfo() getUserInfo()
} catch (e: Exception) { } catch (e: Exception) {
@@ -285,15 +288,44 @@ class LoginActivity : CKBaseActivity() {
} }
private fun quickLogin() {
showProgeassDialog(getString(R.string.login))
TTHttpClient.postJson(this, "登录", TTRequestParam().apply {
add(TTRequestData("username", "13305376054"))
add(TTRequestData("password", "000000"))
add(TTRequestData("code", ""))
add(TTRequestData("uuid", TTUtils.getDeviceId(this@LoginActivity).toString()))
}, object : ICallback {
override fun onSuccess(data: String) {
try {
val model = Gson().fromJson<LoginModel>(data, LoginModel::class.java)
CKApp.app.setLoginToken(model.token.orEmpty())
getUserInfo()
} catch (e: Exception) {
hiddenProgeassDialog()
toast(e.message.orEmpty())
}
}
override fun onFailed(code: String, msg: String) {
hiddenProgeassDialog()
toast(msg)
}
})
}
fun getUserInfo(){ fun getUserInfo(){
TTHttpClient.get(this,"个人资料", TTRequestParam(),object : ICallback{ TTHttpClient.get(this,"个人资料", TTRequestParam(),object : ICallback{
override fun onSuccess(data: String) { override fun onSuccess(data: String) {
CKApp.app.userInfo = Gson().fromJson<UserInfoModel>(data, UserInfoModel::class.java) CKApp.app.userInfo = Gson().fromJson<UserInfoModel>(data, UserInfoModel::class.java)
PreferencesUtils.putString(this@LoginActivity, Const.USER_DATA,data) PreferencesUtils.putString(this@LoginActivity, Const.USER_DATA,data)
toActivity(MainActivity::class.java, DataCollection()) startActivity(
Intent(this@LoginActivity, MainActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
putExtra(MainActivity.EXTRA_SHOW_HOME, true)
}
)
finish() finish()
} }
@@ -308,7 +340,9 @@ class LoginActivity : CKBaseActivity() {
binding.editLoginName.setText(PreferencesUtils.getString(this, Const.LOGIN_NAME, "")) binding.editLoginName.setText(PreferencesUtils.getString(this, Const.LOGIN_NAME, ""))
isCheck = PreferencesUtils.getBolean(this, Const.AGREEMENT_CHECK, false) as Boolean // Agreement consent is intentionally session-local: users must confirm it on every login.
isCheck = false
setCheckUI()
} }
@@ -324,6 +358,12 @@ class LoginActivity : CKBaseActivity() {
} }
fun wxLogin(code : String){ fun wxLogin(code : String){
if (!isCheck) {
toast(getString(R.string.alert_agreement))
return
}
showProgeassDialog(getString(R.string.login)) showProgeassDialog(getString(R.string.login))
TTHttpClient.postJson(this,"微信登录", TTRequestParam().apply { add(TTRequestData("code",code)) },object : ICallback{ TTHttpClient.postJson(this,"微信登录", TTRequestParam().apply { add(TTRequestData("code",code)) },object : ICallback{
override fun onSuccess(data: String) { override fun onSuccess(data: String) {
@@ -338,11 +378,7 @@ class LoginActivity : CKBaseActivity() {
finish() finish()
}else{ }else{
PreferencesUtils.putString( CKApp.app.setLoginToken(model.token.orEmpty())
this@LoginActivity,
Const.TOKEN, model.token.toString()
)
CKApp.app.token = model.token.toString()
getUserInfo() getUserInfo()
} }

View File

@@ -122,11 +122,7 @@ class RegisterActivity : CKBaseActivity() {
try { try {
var model = Gson().fromJson<LoginModel>(data, LoginModel::class.java) var model = Gson().fromJson<LoginModel>(data, LoginModel::class.java)
PreferencesUtils.putString( CKApp.app.setLoginToken(model.token.orEmpty())
this@RegisterActivity,
Const.TOKEN, model.token.toString()
)
CKApp.app.token = model.token.toString()
getUserInfo() getUserInfo()
} catch (e: Exception) { } catch (e: Exception) {

View File

@@ -8,45 +8,42 @@ import android.widget.ImageButton
import com.ck.ckcollar.app.CKApp import com.ck.ckcollar.app.CKApp
import com.ck.ckcollar.app.R import com.ck.ckcollar.app.R
import com.ck.ckcollar.app.databinding.ActivityMemberBinding import com.ck.ckcollar.app.databinding.ActivityMemberBinding
import com.ck.ckcollar.app.model.MemberModel
import com.ck.ckcollar.app.model.MemberPriceModel import com.ck.ckcollar.app.model.MemberPriceModel
import com.ck.ckcollar.app.model.PointsModel
import com.ck.ckcollar.app.model.RecordModel
import com.ck.ckcollar.app.model.UserInfoModel import com.ck.ckcollar.app.model.UserInfoModel
import com.ck.ckcollar.app.ui.base.CKBaseActivity import com.ck.ckcollar.app.ui.base.CKBaseActivity
import com.ck.ckcollar.app.utils.CKUtils import com.ck.ckcollar.app.utils.CKUtils
import com.ck.ckcollar.app.utils.Const
import com.ck.ckcollar.app.utils.MemberPriceCache
import com.ck.ckcollar.app.utils.networkone.ICallback import com.ck.ckcollar.app.utils.networkone.ICallback
import com.ck.ckcollar.app.utils.networkone.TTHttpClient import com.ck.ckcollar.app.utils.networkone.TTHttpClient
import com.ck.ckcollar.app.utils.networkone.model.TTRequestParam import com.ck.ckcollar.app.utils.networkone.model.TTRequestParam
import com.cyclone.shadowsocks.utils.PreferencesUtils
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.reflect.TypeToken import com.google.gson.reflect.TypeToken
import com.gyf.immersionbar.ImmersionBar
import com.tt.kit.base.TTBaseActivity
import com.tt.kit.model.DataCollection import com.tt.kit.model.DataCollection
class MemberActivity : CKBaseActivity() { class MemberActivity : CKBaseActivity() {
override val useDarkStatusBarIcons: Boolean = false
lateinit var binding: ActivityMemberBinding lateinit var binding: ActivityMemberBinding
private var priceRequestInFlight = false
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
binding = ActivityMemberBinding.inflate(layoutInflater) binding = ActivityMemberBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
// ImmersionBar.with(this)
// .statusBarDarkFont(true)
// .init()
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setActionBarColor(resources.getColor(R.color.color_252132)) setActionBarColor(resources.getColor(R.color.color_252132))
setStatusBarColor2(resources.getColor(R.color.color_252132)) setStatusBarColor2(resources.getColor(R.color.color_252132))
findViewById<ImageButton>(R.id.btnLeft).imageTintList = ColorStateList.valueOf(Color.WHITE) findViewById<ImageButton>(R.id.btnLeft).imageTintList =
ColorStateList.valueOf(Color.WHITE)
setTitleTextColor(resources.getColor(R.color.white)) setTitleTextColor(resources.getColor(R.color.white))
setTitleText(getString(R.string.member)) setTitleText(getString(R.string.member))
} }
override fun initView() { override fun initView() {
binding.btnOpen.setOnClickListener { binding.btnOpen.setOnClickListener {
toActivity(OpenMemberActivity::class.java, DataCollection()) toActivity(OpenMemberActivity::class.java, DataCollection())
} }
@@ -56,8 +53,7 @@ class MemberActivity : CKBaseActivity() {
} }
override fun initData() { override fun initData() {
renderMemberInfo(CKApp.app.userInfo)
} }
override fun onStart() { override fun onStart() {
@@ -65,15 +61,54 @@ class MemberActivity : CKBaseActivity() {
getMemberInfo() getMemberInfo()
} }
fun getInfo() { private fun loadMemberPrice() {
TTHttpClient.get(this, "会员套餐列表", TTRequestParam(), object : ICallback { val cachedPrice = MemberPriceCache.getPrice(this)
override fun onSuccess(data: String) { if (cachedPrice != null) {
var model = Gson().fromJson<List<MemberPriceModel>>(data, object : TypeToken<List<MemberPriceModel>>(){}.type) showMemberPrice(cachedPrice)
if (model.size > 0){
binding.textMoney.text = model.get(0).actualPrice.toString()
} }
if (cachedPrice == null || MemberPriceCache.isExpired(this)) {
getInfo(cachedPrice != null)
}
}
private fun getInfo(hasCachedPrice: Boolean) {
if (priceRequestInFlight) return
priceRequestInFlight = true
TTHttpClient.get(this, "会员套餐列表", TTRequestParam(), object : ICallback {
override fun onSuccess(data: String) {
priceRequestInFlight = false
val model = Gson().fromJson<List<MemberPriceModel>>(
data,
object : TypeToken<List<MemberPriceModel>>() {}.type
)
if (model.isNotEmpty()) {
val price = model.first().actualPrice
MemberPriceCache.save(this@MemberActivity, price)
showMemberPrice(price)
}
}
override fun onFailed(code: String, msg: String) {
priceRequestInFlight = false
if (!hasCachedPrice) toast(msg)
}
})
}
private fun showMemberPrice(price: Double) {
binding.textMoney.text = price.toString()
binding.priceContent.visibility = View.VISIBLE
}
private fun getMemberInfo() {
TTHttpClient.get(this, "个人资料", TTRequestParam(), object : ICallback {
override fun onSuccess(data: String) {
val model = Gson().fromJson<UserInfoModel>(data, UserInfoModel::class.java)
CKApp.app.userInfo = model
PreferencesUtils.putString(this@MemberActivity, Const.USER_DATA, data)
renderMemberInfo(model)
} }
override fun onFailed(code: String, msg: String) { override fun onFailed(code: String, msg: String) {
@@ -82,28 +117,22 @@ class MemberActivity : CKBaseActivity() {
}) })
} }
fun getMemberInfo(){ private fun renderMemberInfo(model: UserInfoModel?) {
TTHttpClient.get(this,"个人资料", TTRequestParam(),object : ICallback{ if (model?.isMember == true) {
override fun onSuccess(data: String) { binding.textMemberDate.text = getString(
var model = Gson().fromJson<UserInfoModel>(data, UserInfoModel::class.java) R.string.deadline_date,
CKUtils.dataToFormat(
model.deadlineTime,
if (model.isMember == true){ CKUtils.YYYYMMDD_HHMMSS,
binding.textMemberDate.text = getString(R.string.deadline_date, CKUtils.dataToFormat(model.deadlineTime, CKUtils.YYYYMMDD
CKUtils.YYYYMMDD_HHMMSS, CKUtils.YYYYMMDD)) )
)
binding.conetnt1.visibility = View.GONE binding.conetnt1.visibility = View.GONE
binding.conetnt2.visibility = View.VISIBLE binding.conetnt2.visibility = View.VISIBLE
} else { } else {
binding.conetnt1.visibility = View.VISIBLE binding.conetnt1.visibility = View.VISIBLE
binding.conetnt2.visibility = View.GONE binding.conetnt2.visibility = View.GONE
loadMemberPrice()
getInfo()
} }
} }
override fun onFailed(code: String, msg: String) {
toast(msg)
}
})
}
} }

View File

@@ -1,5 +1,6 @@
package com.ck.ckcollar.app.ui.act.member package com.ck.ckcollar.app.ui.act.member
import android.content.pm.ApplicationInfo
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.graphics.Color import android.graphics.Color
import android.os.Bundle import android.os.Bundle
@@ -8,6 +9,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.TextView import android.widget.TextView
import com.alipay.sdk.app.EnvUtils
import com.alipay.sdk.app.PayTask import com.alipay.sdk.app.PayTask
import com.ck.ckcollar.app.R import com.ck.ckcollar.app.R
import com.ck.ckcollar.app.databinding.ActivityMemberBinding import com.ck.ckcollar.app.databinding.ActivityMemberBinding
@@ -19,14 +21,19 @@ import com.ck.ckcollar.app.model.PayResult
import com.ck.ckcollar.app.ui.act.shop.PayPasswordBottomFragment import com.ck.ckcollar.app.ui.act.shop.PayPasswordBottomFragment
import com.ck.ckcollar.app.ui.base.CKBaseActivity import com.ck.ckcollar.app.ui.base.CKBaseActivity
import com.ck.ckcollar.app.ui.base.CKLHBaseActionBarActivity import com.ck.ckcollar.app.ui.base.CKLHBaseActionBarActivity
import com.ck.ckcollar.app.ui.act.balance.RechargeActivity
import com.ck.ckcollar.app.utils.Const
import com.ck.ckcollar.app.utils.networkone.ICallback import com.ck.ckcollar.app.utils.networkone.ICallback
import com.ck.ckcollar.app.utils.networkone.TTHttpClient import com.ck.ckcollar.app.utils.networkone.TTHttpClient
import com.ck.ckcollar.app.utils.networkone.model.TTRequestData import com.ck.ckcollar.app.utils.networkone.model.TTRequestData
import com.ck.ckcollar.app.utils.networkone.model.TTRequestParam import com.ck.ckcollar.app.utils.networkone.model.TTRequestParam
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.reflect.TypeToken import com.google.gson.reflect.TypeToken
import com.tencent.mm.opensdk.modelpay.PayReq
import com.tencent.mm.opensdk.openapi.WXAPIFactory
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
import com.tt.kit.utils.TTUtils import com.tt.kit.utils.TTUtils
import com.tt.kit.utils.LiveDataBus
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -38,7 +45,7 @@ class OpenMemberActivity : CKLHBaseActionBarActivity() {
var data = listOf<MemberPriceModel>() var data = listOf<MemberPriceModel>()
var pos = -1 var pos = -1
var isAuto = false var isAuto = false
var payType = "1" var payType = "0"
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
binding = ActivityOpenMemberBinding.inflate(layoutInflater) binding = ActivityOpenMemberBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
@@ -53,6 +60,17 @@ class OpenMemberActivity : CKLHBaseActionBarActivity() {
override fun initView() { override fun initView() {
LiveDataBus.get().with(RechargeActivity.WX_PAY_RESULT, Int::class.java).observe(this) { result ->
when (result) {
0 -> {
toast(getString(R.string.payment_success))
finish()
}
-2 -> toast("已取消微信支付")
else -> toast(getString(R.string.payment_faild))
}
}
//setPriceUI() //setPriceUI()
binding.btnAli.setOnClickListener { binding.btnAli.setOnClickListener {
@@ -134,6 +152,8 @@ class OpenMemberActivity : CKLHBaseActionBarActivity() {
var model = Gson().fromJson<MemberModel>(data, MemberModel::class.java) var model = Gson().fromJson<MemberModel>(data, MemberModel::class.java)
if ("1".equals(payType)){ if ("1".equals(payType)){
aliPay(model.orderStr!!) aliPay(model.orderStr!!)
}else if ("0".equals(payType)) {
wxPay(model)
}else{ }else{
toast(getString(R.string.payment_success)) toast(getString(R.string.payment_success))
finish() finish()
@@ -220,7 +240,10 @@ class OpenMemberActivity : CKLHBaseActionBarActivity() {
fun aliPay(orderStr : String){ fun aliPay(orderStr : String){
GlobalScope.launch(Dispatchers.IO){ GlobalScope.launch(Dispatchers.IO){
// [支付宝沙箱测试] 仅 Debug 包启用Release 包继续使用正式环境。
if (applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE != 0) {
// EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX)
}
val alipay = PayTask(this@OpenMemberActivity) val alipay = PayTask(this@OpenMemberActivity)
val result = alipay.payV2(orderStr, true) val result = alipay.payV2(orderStr, true)
@@ -239,4 +262,49 @@ class OpenMemberActivity : CKLHBaseActionBarActivity() {
} }
} }
} }
private fun wxPay(model: MemberModel) {
val requiredValues = listOf(
model.appId,
model.partnerId,
model.prepayId,
model.packageVal,
model.nonceStr,
model.timeStamp,
model.paySign
)
if (requiredValues.any { it.isNullOrBlank() }) {
hiddenProgeassDialog()
toast("微信支付参数不完整,请检查商户号等支付参数")
return
}
if (model.appId != Const.WX_APP_ID) {
hiddenProgeassDialog()
toast("微信支付 AppID 不匹配")
return
}
val api = WXAPIFactory.createWXAPI(this, Const.WX_APP_ID, true)
api.registerApp(Const.WX_APP_ID)
if (!api.isWXAppInstalled) {
hiddenProgeassDialog()
toast("请先安装微信")
return
}
val request = PayReq().apply {
appId = model.appId
partnerId = model.partnerId
prepayId = model.prepayId
packageValue = model.packageVal
nonceStr = model.nonceStr
timeStamp = model.timeStamp
sign = model.paySign
extData = model.orderNo
}
hiddenProgeassDialog()
if (!api.sendReq(request)) {
toast("微信支付拉起失败")
}
}
} }

View File

@@ -1,5 +1,6 @@
package com.ck.ckcollar.app.ui.act.mine package com.ck.ckcollar.app.ui.act.mine
import android.Manifest
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
@@ -10,24 +11,23 @@ import android.text.TextUtils
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.webkit.MimeTypeMap
import android.widget.AdapterView import android.widget.AdapterView
import android.widget.BaseAdapter import android.widget.BaseAdapter
import android.widget.ImageView import android.widget.ImageView
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import androidx.lifecycle.lifecycleScope
import com.ck.ckcollar.app.R import com.ck.ckcollar.app.R
import com.ck.ckcollar.app.databinding.ActivityFeedBackBinding import com.ck.ckcollar.app.databinding.ActivityFeedBackBinding
import com.ck.ckcollar.app.databinding.LayoutItemImage2Binding import com.ck.ckcollar.app.databinding.LayoutItemImage2Binding
import com.ck.ckcollar.app.databinding.LayoutItemImageBinding
import com.ck.ckcollar.app.model.ImageModel import com.ck.ckcollar.app.model.ImageModel
import com.ck.ckcollar.app.model.UploadModel import com.ck.ckcollar.app.model.UploadModel
import com.ck.ckcollar.app.ui.act.petmanager.AddPetActivity
import com.ck.ckcollar.app.ui.act.petmanager.AddPetActivity.ImageAdapter
import com.ck.ckcollar.app.ui.act.petmanager.ImageViewActivity import com.ck.ckcollar.app.ui.act.petmanager.ImageViewActivity
import com.ck.ckcollar.app.ui.base.CKBaseActivity import com.ck.ckcollar.app.ui.base.CKBaseActivity
import com.ck.ckcollar.app.ui.dialog.CKAlertDialog import com.ck.ckcollar.app.ui.dialog.CKAlertDialog
import com.ck.ckcollar.app.ui.dialog.CKPhotoDialog import com.ck.ckcollar.app.ui.dialog.CKPhotoDialog
import com.ck.ckcollar.app.utils.CKUtils
import com.ck.ckcollar.app.utils.Const import com.ck.ckcollar.app.utils.Const
import com.ck.ckcollar.app.utils.LubanCompressUtil
import com.ck.ckcollar.app.utils.networkone.ICallback import com.ck.ckcollar.app.utils.networkone.ICallback
import com.ck.ckcollar.app.utils.networkone.TTHttpClient import com.ck.ckcollar.app.utils.networkone.TTHttpClient
import com.ck.ckcollar.app.utils.networkone.model.TTRequestData import com.ck.ckcollar.app.utils.networkone.model.TTRequestData
@@ -36,8 +36,10 @@ import com.cyclone.shadowsocks.utils.PreferencesUtils
import com.google.gson.Gson import com.google.gson.Gson
import com.tt.kit.model.Data import com.tt.kit.model.Data
import com.tt.kit.model.DataCollection import com.tt.kit.model.DataCollection
import com.tt.kit.utils.TTLog
import com.tt.kit.utils.TTUtils import com.tt.kit.utils.TTUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File import java.io.File
class FeedBackActivity : CKBaseActivity() { class FeedBackActivity : CKBaseActivity() {
@@ -50,7 +52,7 @@ class FeedBackActivity : CKBaseActivity() {
binding = ActivityFeedBackBinding.inflate(layoutInflater) binding = ActivityFeedBackBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
checkAppPermissions() // checkAppPermissions()
setTitleText(getString(R.string.feedback)) setTitleText(getString(R.string.feedback))
} }
@@ -84,13 +86,30 @@ class FeedBackActivity : CKBaseActivity() {
}) })
return return
} }
//相册 CKPhotoDialog(
val i = Intent( this@FeedBackActivity,
Intent.ACTION_PICK, object : CKPhotoDialog.PhotoClickListener {
MediaStore.Images.Media.EXTERNAL_CONTENT_URI override fun onBack(mark: Int, position: Int) {
try {
if (mark == 0) {
if (!checkCameraPermissions()) {
getPermissionRequst(
Manifest.permission.CAMERA,
REQUEST_CAMERA_PERMISSION
) )
i.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,"image/*"); return
startActivityForResult(i, 56) }
takePhoto()
} else {
openAlbum()
}
} catch (e: Exception) {
e.printStackTrace()
toast(getString(R.string.read_photo_failed))
}
}
}
).show()
} }
} }
@@ -105,6 +124,12 @@ class FeedBackActivity : CKBaseActivity() {
} }
override fun onPermissionsGranted(requestCode: Int, permissions: Array<String>) {
if (requestCode == REQUEST_CAMERA_PERMISSION) {
takePhoto()
}
}
fun upload(){ fun upload(){
if (binding.editConten.isEmpty()){ if (binding.editConten.isEmpty()){
@@ -162,12 +187,121 @@ class FeedBackActivity : CKBaseActivity() {
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 56 && resultCode == RESULT_OK) { if (requestCode == REQUEST_CAMERA && resultCode == RESULT_OK) {
var path = TTUtils.getImageUrl(this, data!!.getData()); val path = PreferencesUtils.getString(this, Const.IMAGE_PATH, "").orEmpty()
this.data.add(this.data.size - 1,ImageModel().apply { this.path = path }) compressAndAddImage(path)
imageAdapter.data = this.data } else if (requestCode == REQUEST_ALBUM && resultCode == RESULT_OK) {
data?.data?.let(::handleSelectedImage)
?: toast(getString(R.string.read_photo_failed))
}
}
private fun openAlbum() {
val intent = Intent(
Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
).apply {
setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*")
}
startActivityForResult(intent, REQUEST_ALBUM)
}
private fun handleSelectedImage(uri: Uri) {
lifecycleScope.launch {
val path = withContext(Dispatchers.IO) {
copySelectedImageToCache(uri)
}
if (path == null) {
toast(getString(R.string.read_photo_failed))
return@launch
}
compressAndAddImage(path)
}
}
private fun compressAndAddImage(path: String) {
if (path.isBlank()) {
toast(getString(R.string.read_photo_failed))
return
}
LubanCompressUtil.getCompressFile(
this,
File(path),
object : LubanCompressUtil.CompressCallback {
override fun success(file: File) {
if (isFinishing || isDestroyed) return
data.add(data.size - 1, ImageModel().apply {
this.path = file.absolutePath
})
imageAdapter.data = data
imageAdapter.notifyDataSetChanged() imageAdapter.notifyDataSetChanged()
} }
override fun fail(failMsg: String) {
if (isFinishing || isDestroyed) return
toast(failMsg)
}
}
)
}
private fun copySelectedImageToCache(uri: Uri): String? {
val extension = contentResolver.getType(uri)
?.let(MimeTypeMap.getSingleton()::getExtensionFromMimeType)
?.takeIf { it.isNotBlank() }
?: "jpg"
val imageDir = File(cacheDir, "feedback_images")
if (!imageDir.exists() && !imageDir.mkdirs()) return null
val target = File(imageDir, System.currentTimeMillis().toString() + "." + extension)
return try {
val input = contentResolver.openInputStream(uri) ?: return null
input.use { source ->
target.outputStream().use { output -> source.copyTo(output) }
}
target.absolutePath.takeIf { target.length() > 0L }
?: run {
target.delete()
null
}
} catch (e: Exception) {
target.delete()
e.printStackTrace()
null
}
}
private fun takePhoto() {
try {
val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
val imageFile = File(
getExternalFilesDir(Environment.DIRECTORY_PICTURES),
System.currentTimeMillis().toString() + ".png"
)
imageFile.parentFile?.let { parent ->
if (!parent.exists()) parent.mkdirs()
}
PreferencesUtils.putString(this, Const.IMAGE_PATH, imageFile.absolutePath)
val cameraUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
FileProvider.getUriForFile(
this,
packageName + ".fileprovider",
imageFile
)
} else {
Uri.fromFile(imageFile)
}
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, cameraUri)
cameraIntent.addFlags(
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
startActivityForResult(cameraIntent, REQUEST_CAMERA)
} catch (e: Exception) {
e.printStackTrace()
toast(getString(R.string.read_photo_failed))
}
} }
@@ -234,4 +368,10 @@ class FeedBackActivity : CKBaseActivity() {
} }
} }
companion object {
private const val REQUEST_CAMERA = 55
private const val REQUEST_ALBUM = 56
private const val REQUEST_CAMERA_PERMISSION = 1301
}
} }

View File

@@ -23,7 +23,7 @@ class ReturnDeviceActivity : CKBaseActivity() {
binding = ActivityReturnDeviceBinding.inflate(layoutInflater) binding = ActivityReturnDeviceBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
checkAppPermissions() // checkAppPermissions()
setTitleText(getString(R.string.device_return)) setTitleText(getString(R.string.device_return))
setActionBarColor(getColor(R.color.white)) setActionBarColor(getColor(R.color.white))
@@ -97,6 +97,12 @@ class ReturnDeviceActivity : CKBaseActivity() {
return return
} }
val phone = binding.textPhone.text.toString().trim()
if (!PHONE_PATTERN.matches(phone)) {
toast(getString(R.string.invalid_phone_format))
return
}
if (binding.textReason.isEmpty()){ if (binding.textReason.isEmpty()){
toast(getString(R.string.input_return_reason)) toast(getString(R.string.input_return_reason))
return return
@@ -124,4 +130,8 @@ class ReturnDeviceActivity : CKBaseActivity() {
} }
}) })
} }
companion object {
private val PHONE_PATTERN = Regex("^1[3-9]\\d{9}$")
}
} }

View File

@@ -137,7 +137,7 @@ class LogisticsInfoActivity : CKBaseActivity() {
model = Gson().fromJson<OrderModel.Order>(getReceiveParam().get("data")!!.stringValue.toString(), model = Gson().fromJson<OrderModel.Order>(getReceiveParam().get("data")!!.stringValue.toString(),
OrderModel.Order::class.java) OrderModel.Order::class.java)
binding.textReceiveName.text = model.receiverName + " " + model.receiverPhone binding.textReceiveName.text = model.receiverAddress + "\n" + model.receiverName + " " + model.receiverPhone
getData() getData()
} }

View File

@@ -160,6 +160,7 @@ class MyOrderActivity : CKBaseActivity() , View.OnClickListener{
fun getData() { fun getData() {
showProgeassDialog()
TTHttpClient.get(this, "我的订单", TTRequestParam().apply { TTHttpClient.get(this, "我的订单", TTRequestParam().apply {
add( add(
TTRequestData("pageNum", page) TTRequestData("pageNum", page)
@@ -172,10 +173,10 @@ class MyOrderActivity : CKBaseActivity() , View.OnClickListener{
override fun onSuccess(data: String) { override fun onSuccess(data: String) {
var model = Gson().fromJson<OrderModel>(data, OrderModel::class.java) var model = Gson().fromJson<OrderModel>(data, OrderModel::class.java)
model.rows?.let{
if (page == 1) { if (page == 1) {
this@MyOrderActivity.data.clear() this@MyOrderActivity.data.clear()
} }
model.rows?.let{
if (this@MyOrderActivity.data.size != model.total){ if (this@MyOrderActivity.data.size != model.total){
this@MyOrderActivity.data.addAll(model.rows!!) this@MyOrderActivity.data.addAll(model.rows!!)
} }
@@ -184,11 +185,17 @@ class MyOrderActivity : CKBaseActivity() , View.OnClickListener{
orderAdapter.data = this@MyOrderActivity.data orderAdapter.data = this@MyOrderActivity.data
orderAdapter.notifyDataSetChanged() orderAdapter.notifyDataSetChanged()
val isEmpty = this@MyOrderActivity.data.isEmpty()
binding.relNoresult.visibility = if (isEmpty) View.VISIBLE else View.GONE
binding.recyclerView.visibility = if (isEmpty) View.GONE else View.VISIBLE
binding.refreshLayout.finishRefresh() binding.refreshLayout.finishRefresh()
binding.refreshLayout.finishLoadMore(true) binding.refreshLayout.finishLoadMore(true)
} }
override fun onFailed(code: String, msg: String) { override fun onFailed(code: String, msg: String) {
binding.refreshLayout.finishRefresh()
binding.refreshLayout.finishLoadMore(false)
toast(msg) toast(msg)
} }
}) })

View File

@@ -1,6 +1,7 @@
package com.ck.ckcollar.app.ui.act.order package com.ck.ckcollar.app.ui.act.order
import android.content.Context import android.content.Context
import android.content.pm.ApplicationInfo
import android.os.Bundle import android.os.Bundle
import android.text.TextUtils import android.text.TextUtils
import android.view.LayoutInflater import android.view.LayoutInflater
@@ -8,6 +9,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.alipay.sdk.app.EnvUtils
import com.alipay.sdk.app.PayTask import com.alipay.sdk.app.PayTask
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.ck.ckcollar.app.CKApp import com.ck.ckcollar.app.CKApp
@@ -20,27 +22,34 @@ import com.ck.ckcollar.app.model.AddressModel
import com.ck.ckcollar.app.model.ConfirmOrderModel import com.ck.ckcollar.app.model.ConfirmOrderModel
import com.ck.ckcollar.app.model.MemberModel import com.ck.ckcollar.app.model.MemberModel
import com.ck.ckcollar.app.model.OrderModel import com.ck.ckcollar.app.model.OrderModel
import com.ck.ckcollar.app.model.OrderPaymentModel
import com.ck.ckcollar.app.model.PayOrderModel import com.ck.ckcollar.app.model.PayOrderModel
import com.ck.ckcollar.app.model.PayPasswordStatus import com.ck.ckcollar.app.model.PayPasswordStatus
import com.ck.ckcollar.app.model.PayResult import com.ck.ckcollar.app.model.PayResult
import com.ck.ckcollar.app.model.UserInfoModel import com.ck.ckcollar.app.model.UserInfoModel
import com.ck.ckcollar.app.ui.act.setting.PayPsswordActivity import com.ck.ckcollar.app.ui.act.setting.PayPsswordActivity
import com.ck.ckcollar.app.ui.act.balance.RechargeActivity
import com.ck.ckcollar.app.ui.act.shop.OrderSuccessActivity import com.ck.ckcollar.app.ui.act.shop.OrderSuccessActivity
import com.ck.ckcollar.app.ui.act.shop.PayPasswordBottomFragment import com.ck.ckcollar.app.ui.act.shop.PayPasswordBottomFragment
import com.ck.ckcollar.app.ui.base.CKBaseActivity import com.ck.ckcollar.app.ui.base.CKBaseActivity
import com.ck.ckcollar.app.utils.CKUtils import com.ck.ckcollar.app.utils.CKUtils
import com.ck.ckcollar.app.utils.Const
import com.ck.ckcollar.app.utils.networkone.ICallback import com.ck.ckcollar.app.utils.networkone.ICallback
import com.ck.ckcollar.app.utils.networkone.TTHttpClient import com.ck.ckcollar.app.utils.networkone.TTHttpClient
import com.ck.ckcollar.app.utils.networkone.model.TTRequestData import com.ck.ckcollar.app.utils.networkone.model.TTRequestData
import com.ck.ckcollar.app.utils.networkone.model.TTRequestParam import com.ck.ckcollar.app.utils.networkone.model.TTRequestParam
import com.google.gson.Gson import com.google.gson.Gson
import com.tencent.mm.opensdk.modelpay.PayReq
import com.tencent.mm.opensdk.openapi.WXAPIFactory
import com.tt.kit.model.Data import com.tt.kit.model.Data
import com.tt.kit.model.DataCollection import com.tt.kit.model.DataCollection
import com.tt.kit.utils.LiveDataBus
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.math.BigDecimal import java.math.BigDecimal
import java.math.RoundingMode
class PayOrderActivity : CKBaseActivity() { class PayOrderActivity : CKBaseActivity() {
@@ -54,12 +63,15 @@ class PayOrderActivity : CKBaseActivity() {
var memberModel: UserInfoModel? = null var memberModel: UserInfoModel? = null
var payType = "1" var payType = "0"
var selectBalance = false var selectBalance = false
var selectPoints = false var selectPoints = false
var confirmOrderModel : ConfirmOrderModel? = null var confirmOrderModel : ConfirmOrderModel? = null
lateinit var orderSource: String lateinit var orderSource: String
private var isCancellingOrder = false
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
binding = ActivityPayOrderBinding.inflate(layoutInflater) binding = ActivityPayOrderBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
@@ -68,6 +80,14 @@ class PayOrderActivity : CKBaseActivity() {
} }
override fun initView() { override fun initView() {
LiveDataBus.get().with(RechargeActivity.WX_PAY_RESULT, Int::class.java).observe(this) { result ->
if (result == 0) {
handleWeChatPaymentSuccess()
} else {
handleWeChatPaymentFailed(result == -2)
}
}
productAdapter = productAdapter =
ProductAdapter(this@PayOrderActivity, productDatas, object : OnItemClickListenner { ProductAdapter(this@PayOrderActivity, productDatas, object : OnItemClickListenner {
override fun onClick(pos: Int, model: Any) { override fun onClick(pos: Int, model: Any) {
@@ -82,13 +102,14 @@ class PayOrderActivity : CKBaseActivity() {
binding.btnAli.setOnClickListener(payClick) binding.btnAli.setOnClickListener(payClick)
binding.btnWX.setOnClickListener(payClick) binding.btnWX.setOnClickListener(payClick)
binding.btnBalance.setOnClickListener(payClick)
binding.btnPoints.setOnClickListener(payClick)
binding.btnBalance.setOnClickListener { binding.btnBalance.setOnClickListener {
if (memberModel?.balance == 0.0){ if (clearBalanceIfPointsSufficient()) {
toast("积分足够无需使用余额")
return@setOnClickListener
}
if ((memberModel?.balance ?: 0.0) <= 0.0){
toast(getString(R.string.balance_over)) toast(getString(R.string.balance_over))
return@setOnClickListener return@setOnClickListener
} }
@@ -99,21 +120,28 @@ class PayOrderActivity : CKBaseActivity() {
}else{ }else{
binding.image3.setImageResource(R.mipmap.image_address_check_narmal) binding.image3.setImageResource(R.mipmap.image_address_check_narmal)
} }
clearExternalPaymentIfNotNeeded()
} }
binding.btnPoints.setOnClickListener { binding.btnPoints.setOnClickListener {
if ((memberModel?.points ?: 0.0) <= 0.0) {
toast(getString(R.string.points_over))
return@setOnClickListener
}
selectPoints = !selectPoints selectPoints = !selectPoints
if (selectPoints){ if (selectPoints){
binding.image4.setImageResource(R.mipmap.image_address_check_select) binding.image4.setImageResource(R.mipmap.image_address_check_select)
}else{ }else{
binding.image4.setImageResource(R.mipmap.image_address_check_narmal) binding.image4.setImageResource(R.mipmap.image_address_check_narmal)
} }
clearBalanceIfPointsSufficient()
clearExternalPaymentIfNotNeeded()
} }
binding.btnBuyNow.setOnClickListener { binding.btnBuyNow.setOnClickListener {
if (selectBalance && !canPointsCoverPayAmount()){
if (selectBalance){
getPayPassword() getPayPassword()
}else{ }else{
order("") order("")
@@ -170,7 +198,7 @@ class PayOrderActivity : CKBaseActivity() {
if (TextUtils.isEmpty(payType) && memberModel?.balance == 0.0){ if (TextUtils.isEmpty(payType) && memberModel?.balance == 0.0){
if (!selectPoints || "1".equals(confirmOrderModel?.isPoint)){ if (!selectPoints || "1".equals(confirmOrderModel?.isPoint.toString())){
toast(getString(R.string.balance_over)) toast(getString(R.string.balance_over))
return return
} }
@@ -204,17 +232,18 @@ class PayOrderActivity : CKBaseActivity() {
fun showPayBottomView(){ fun showPayBottomView(){
var showBalance = model.payAmount var showBalance = BigDecimal.valueOf(model.payAmount).setScale(2, RoundingMode.HALF_UP)
if (selectPoints){ if (selectPoints){
CKApp.app.userInfo?.intoAmounts?.let { calculatePointsDeduction()?.let { pointsDeduction ->
showBalance = showBalance - BigDecimal(memberModel?.points!!).multiply( showBalance = showBalance.subtract(pointsDeduction)
BigDecimal(memberModel!!.intoAmounts!!)).setScale(2).toDouble() .max(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP))
if (showBalance < 0.0){
showBalance = 0.00
}
} }
} }
val userBalance = BigDecimal.valueOf(memberModel?.balance ?: 0.0)
.setScale(2, RoundingMode.HALF_UP)
showBalance = showBalance.min(userBalance)
var passwordBottomFragment = PayPasswordBottomFragment(showBalance.toString(), "余额",object : PayPasswordBottomFragment.PasswordCallBack{ var passwordBottomFragment = PayPasswordBottomFragment(showBalance.toString(), "余额",object : PayPasswordBottomFragment.PasswordCallBack{
override fun callBack(password: String) { override fun callBack(password: String) {
@@ -229,6 +258,11 @@ class PayOrderActivity : CKBaseActivity() {
var payType = payType var payType = payType
if(selectBalance){ if(selectBalance){
if (TextUtils.isEmpty(payType) && memberModel?.balance == 0.0){
toast(getString(R.string.balance_over))
return
}
if (TextUtils.isEmpty(payType)){ if (TextUtils.isEmpty(payType)){
payType = "2" payType = "2"
}else{ }else{
@@ -236,6 +270,11 @@ class PayOrderActivity : CKBaseActivity() {
} }
} }
if(selectPoints){ if(selectPoints){
if (TextUtils.isEmpty(payType) && memberModel?.points == 0.0){
toast(getString(R.string.points_over))
return
}
if (TextUtils.isEmpty(payType)){ if (TextUtils.isEmpty(payType)){
payType = "3" payType = "3"
}else{ }else{
@@ -271,16 +310,25 @@ class PayOrderActivity : CKBaseActivity() {
) )
}, object : ICallback { }, object : ICallback {
override fun onSuccess(data: String) { override fun onSuccess(data: String) {
var model = Gson().fromJson<PayOrderModel>(data, PayOrderModel::class.java) val paymentModel = Gson().fromJson(data, OrderPaymentModel::class.java)
if ("0".equals(this@PayOrderActivity.payType)) { if ("0".equals(this@PayOrderActivity.payType)) {
//微信 val weChatPayParams = paymentModel.wxMap
if (weChatPayParams == null || !weChatPayParams.isJsonObject) {
hiddenProgeassDialog()
toast("微信支付参数格式错误")
return
}
wxPay(Gson().fromJson(weChatPayParams, PayOrderModel::class.java))
}else if ("1".equals(this@PayOrderActivity.payType)) { }else if ("1".equals(this@PayOrderActivity.payType)) {
if (TextUtils.isEmpty(model.orderStr)){ val aliPayOrderStr = paymentModel.orderStr
?.takeIf { it.isJsonPrimitive && it.asJsonPrimitive.isString }
?.asString
if (TextUtils.isEmpty(aliPayOrderStr)){
toActivity(OrderSuccessActivity::class.java, DataCollection()) toActivity(OrderSuccessActivity::class.java, DataCollection())
finish(DataCollection(),1002) finish(DataCollection(),1002)
}else{ }else{
aliPay(model.orderStr!!) aliPay(aliPayOrderStr!!)
} }
}else{ }else{
toast(getString(R.string.order_success)) toast(getString(R.string.order_success))
@@ -299,9 +347,143 @@ class PayOrderActivity : CKBaseActivity() {
}) })
} }
fun aliPay(orderStr: String) { private fun wxPay(model: PayOrderModel) {
GlobalScope.launch(Dispatchers.IO) { val requiredValues = listOf(
model.appId,
model.partnerId,
model.prepayId,
model.packageVal,
model.nonceStr,
model.timeStamp,
model.paySign
)
if (requiredValues.any { it.isNullOrBlank() }) {
hiddenProgeassDialog()
toast("微信支付参数不完整,请检查商户号等支付参数")
return
}
if (model.appId != Const.WX_APP_ID) {
hiddenProgeassDialog()
toast("微信支付 AppID 不匹配")
return
}
val api = WXAPIFactory.createWXAPI(this, Const.WX_APP_ID, true)
api.registerApp(Const.WX_APP_ID)
if (!api.isWXAppInstalled) {
hiddenProgeassDialog()
toast("请先安装微信")
return
}
val request = PayReq().apply {
appId = model.appId
partnerId = model.partnerId
prepayId = model.prepayId
packageValue = model.packageVal
nonceStr = model.nonceStr
timeStamp = model.timeStamp
sign = model.paySign
extData = model.orderNo
}
hiddenProgeassDialog()
if (!api.sendReq(request)) {
toast("微信支付拉起失败")
}
}
private fun handleWeChatPaymentSuccess() {
toast(getString(R.string.payment_success))
finish(DataCollection(), 1002)
}
private fun handleWeChatPaymentFailed(cancelled: Boolean) {
if (cancelled) {
cancelPendingOrder()
} else {
toast(getString(R.string.payment_faild))
}
}
private fun cancelPendingOrder() {
if (isCancellingOrder) return
isCancellingOrder = true
showProgeassDialog(getString(R.string.cancel))
TTHttpClient.post(this, "取消待支付订单", TTRequestParam().apply {
add(TTRequestData("orderId", model.id))
}, object : ICallback {
override fun onSuccess(data: String) {
hiddenProgeassDialog()
toast(getString(R.string.cancel_pay_cussess))
finish(DataCollection(), 1002)
}
override fun onFailed(code: String, msg: String) {
isCancellingOrder = false
hiddenProgeassDialog()
toast(msg)
}
})
}
private fun canPointsCoverPayAmount(): Boolean {
if (!selectPoints) return false
val pointsDeduction = calculatePointsDeduction() ?: return false
val payAmount = BigDecimal.valueOf(model.payAmount).setScale(2, RoundingMode.HALF_UP)
return pointsDeduction >= payAmount
}
private fun clearBalanceIfPointsSufficient(): Boolean {
if (!canPointsCoverPayAmount()) return false
selectBalance = false
binding.image3.setImageResource(R.mipmap.image_address_check_narmal)
return true
}
private fun calculatePointsDeduction(): BigDecimal? {
val member = memberModel ?: return null
val intoAmounts = member.intoAmounts?.toBigDecimalOrNull() ?: return null
return BigDecimal.valueOf(member.points)
.multiply(intoAmounts)
.setScale(2, RoundingMode.HALF_UP)
}
private fun isInternalPaymentSufficient(): Boolean {
var internalAmount = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP)
if (selectBalance) {
internalAmount = internalAmount.add(
BigDecimal.valueOf(memberModel?.balance ?: 0.0)
.setScale(2, RoundingMode.HALF_UP)
)
}
if (selectPoints) {
internalAmount = internalAmount.add(
calculatePointsDeduction() ?: BigDecimal.ZERO
)
}
val payAmount = BigDecimal.valueOf(model.payAmount)
.setScale(2, RoundingMode.HALF_UP)
return internalAmount >= payAmount
}
private fun clearExternalPaymentIfNotNeeded() {
if (!isInternalPaymentSufficient()) return
payType = ""
binding.image1.setImageResource(R.mipmap.image_address_check_narmal)
binding.image2.setImageResource(R.mipmap.image_address_check_narmal)
}
fun aliPay(orderStr: String) {
GlobalScope.launch(Dispatchers.IO) {
// [支付宝沙箱测试] 仅 Debug 包启用Release 包继续使用正式环境。
if (applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE != 0) {
// EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX)
}
val alipay = PayTask(this@PayOrderActivity) val alipay = PayTask(this@PayOrderActivity)
val result = alipay.payV2(orderStr, true) val result = alipay.payV2(orderStr, true)
@@ -314,6 +496,8 @@ class PayOrderActivity : CKBaseActivity() {
// 该笔订单是否真实支付成功,需要依赖服务端的异步通知。 // 该笔订单是否真实支付成功,需要依赖服务端的异步通知。
toast(getString(R.string.payment_success)) toast(getString(R.string.payment_success))
finish(DataCollection(),1002) finish(DataCollection(),1002)
} else if (TextUtils.equals(resultStatus, "6001")) {
cancelPendingOrder()
} else { } else {
toast(getString(R.string.payment_faild)) toast(getString(R.string.payment_faild))
} }
@@ -349,6 +533,12 @@ class PayOrderActivity : CKBaseActivity() {
var payClick = object : View.OnClickListener { var payClick = object : View.OnClickListener {
override fun onClick(v: View?) { override fun onClick(v: View?) {
if (isInternalPaymentSufficient()) {
clearExternalPaymentIfNotNeeded()
toast("当前支付方式无需使用三方支付")
return
}
binding.image1.setImageResource(R.mipmap.image_address_check_narmal) binding.image1.setImageResource(R.mipmap.image_address_check_narmal)
binding.image2.setImageResource(R.mipmap.image_address_check_narmal) binding.image2.setImageResource(R.mipmap.image_address_check_narmal)
when (v?.id) { when (v?.id) {

View File

@@ -251,10 +251,12 @@ class RefundActivity: CKBaseActivity() {
showProgeassDialog(getString(R.string.submit)) showProgeassDialog(getString(R.string.submit))
var commodityState = if(model.orderStatus >= 3){
"1" var commodityState = -1;
if ("0".equals(refundType)){
commodityState = 0
}else{ }else{
"0" commodityState = 1
} }
var param = TTRequestParam().apply { var param = TTRequestParam().apply {
add(TTRequestData("orderId",model.id)) add(TTRequestData("orderId",model.id))

View File

@@ -1,7 +1,7 @@
package com.ck.ckcollar.app.ui.act.petmanager package com.ck.ckcollar.app.ui.act.petmanager
import android.Manifest
import android.content.Intent import android.content.Intent
import android.graphics.Bitmap
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
@@ -11,10 +11,12 @@ import android.text.TextUtils
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.webkit.MimeTypeMap
import android.widget.AdapterView import android.widget.AdapterView
import android.widget.BaseAdapter import android.widget.BaseAdapter
import android.widget.ImageView import android.widget.ImageView
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import androidx.lifecycle.lifecycleScope
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.ck.ckcollar.app.R import com.ck.ckcollar.app.R
import com.ck.ckcollar.app.databinding.ActivityAddPetBinding import com.ck.ckcollar.app.databinding.ActivityAddPetBinding
@@ -28,6 +30,7 @@ import com.ck.ckcollar.app.ui.dialog.CKPhotoDialog
import com.ck.ckcollar.app.ui.dialog.CKPickViewDialog import com.ck.ckcollar.app.ui.dialog.CKPickViewDialog
import com.ck.ckcollar.app.utils.CKUtils import com.ck.ckcollar.app.utils.CKUtils
import com.ck.ckcollar.app.utils.Const import com.ck.ckcollar.app.utils.Const
import com.ck.ckcollar.app.utils.LubanCompressUtil
import com.ck.ckcollar.app.utils.networkone.ICallback import com.ck.ckcollar.app.utils.networkone.ICallback
import com.ck.ckcollar.app.utils.networkone.TTHttpClient import com.ck.ckcollar.app.utils.networkone.TTHttpClient
import com.ck.ckcollar.app.utils.networkone.model.TTRequestData import com.ck.ckcollar.app.utils.networkone.model.TTRequestData
@@ -40,6 +43,9 @@ import com.tt.kit.model.DataCollection
import com.tt.kit.utils.LiveDataBus import com.tt.kit.utils.LiveDataBus
import com.tt.kit.utils.TTLog import com.tt.kit.utils.TTLog
import com.tt.kit.utils.TTUtils import com.tt.kit.utils.TTUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File import java.io.File
class AddPetActivity : CKBaseActivity() { class AddPetActivity : CKBaseActivity() {
@@ -97,12 +103,10 @@ class AddPetActivity : CKBaseActivity() {
try { try {
if (mark == 0){ if (mark == 0){
if (!checkCameraPermissions()){ if (!checkCameraPermissions()){
CKAlertDialog(this@AddPetActivity,getString(R.string.alert),getString(R.string.camera_alert),object : CKAlertDialog.AlertClickListener{ getPermissionRequst(
override fun onBack(isConfirm: Boolean) { Manifest.permission.CAMERA,
TODO("Not yet implemented") REQUEST_CAMERA_PERMISSION
} )
}).show()
return return
} }
takePhoto() takePhoto()
@@ -189,11 +193,25 @@ class AddPetActivity : CKBaseActivity() {
} }
binding.tvAiRecognize.setOnClickListener { binding.tvAiRecognize.setOnClickListener {
if (!checkCameraPermissions()) {
getPermissionRequst(
Manifest.permission.CAMERA,
REQUEST_AI_CAMERA_PERMISSION
)
return@setOnClickListener
}
takePhoto2() takePhoto2()
} }
} }
override fun onPermissionsGranted(requestCode: Int, permissions: Array<String>) {
when (requestCode) {
REQUEST_CAMERA_PERMISSION -> takePhoto()
REQUEST_AI_CAMERA_PERMISSION -> takePhoto2()
}
}
override fun initData() { override fun initData() {
var data = getReceiveParam().get("data") var data = getReceiveParam().get("data")
data?.let { data?.let {
@@ -271,6 +289,7 @@ class AddPetActivity : CKBaseActivity() {
} }
} }
showProgeassDialog() showProgeassDialog()
//先上传照片
TTHttpClient.postFile(this,"上传照片s", param,object : ICallback{ TTHttpClient.postFile(this,"上传照片s", param,object : ICallback{
override fun onSuccess(data: String) { override fun onSuccess(data: String) {
var model = Gson().fromJson<UploadModel>(data,UploadModel::class.java) var model = Gson().fromJson<UploadModel>(data,UploadModel::class.java)
@@ -317,21 +336,109 @@ class AddPetActivity : CKBaseActivity() {
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 55 && resultCode == RESULT_OK) { if (requestCode == 55 && resultCode == RESULT_OK) {
var path = PreferencesUtils.getString(this@AddPetActivity, Const.IMAGE_PATH,"") val path = PreferencesUtils.getString(this@AddPetActivity, Const.IMAGE_PATH, "")
this.data.add(this.data.size - 1,ImageModel().apply { this.path = path }) compressAndAddImage(path.orEmpty())
imageAdapter.data = this.data
imageAdapter.notifyDataSetChanged()
}else if (requestCode == 56 && resultCode == RESULT_OK) { }else if (requestCode == 56 && resultCode == RESULT_OK) {
var path = TTUtils.getImageUrl(this, data!!.getData()); data?.data?.let(::handleSelectedImage)
this.data.add(this.data.size - 1,ImageModel().apply { this.path = path }) ?: toast(getString(R.string.read_photo_failed))
imageAdapter.data = this.data
imageAdapter.notifyDataSetChanged()
}else if (requestCode == 555 && resultCode == RESULT_OK) { }else if (requestCode == 555 && resultCode == RESULT_OK) {
var path = PreferencesUtils.getString(this@AddPetActivity, Const.IMAGE_PATH,"") val path = PreferencesUtils.getString(this@AddPetActivity, Const.IMAGE_PATH, "")
uploadImage(path!!) compressAndUploadImage(path.orEmpty())
} }
binding.textPhotoNum.setText((this.data.size - 1 ).toString() + "/3") binding.textPhotoNum.setText((this.data.size - 1 ).toString() + "/3")
} }
private fun handleSelectedImage(uri: Uri) {
lifecycleScope.launch {
val path = withContext(Dispatchers.IO) {
copySelectedImageToCache(uri)
}
if (path == null) {
toast(getString(R.string.read_photo_failed))
return@launch
}
compressAndAddImage(path)
}
}
private fun compressAndAddImage(path: String) {
if (path.isBlank()) {
toast(getString(R.string.read_photo_failed))
return
}
LubanCompressUtil.getCompressFile(
this,
File(path),
object : LubanCompressUtil.CompressCallback {
override fun success(file: File) {
if (isFinishing || isDestroyed) return
data.add(data.size - 1, ImageModel().apply {
this.path = file.absolutePath
})
imageAdapter.data = data
imageAdapter.notifyDataSetChanged()
binding.textPhotoNum.text = "${data.size - 1}/3"
}
override fun fail(failMsg: String) {
if (isFinishing || isDestroyed) return
toast(failMsg)
}
}
)
}
private fun compressAndUploadImage(path: String) {
if (path.isBlank()) {
toast(getString(R.string.read_photo_failed))
return
}
LubanCompressUtil.getCompressFile(
this,
File(path),
object : LubanCompressUtil.CompressCallback {
override fun success(file: File) {
if (isFinishing || isDestroyed) return
uploadImage(file.absolutePath)
}
override fun fail(failMsg: String) {
if (isFinishing || isDestroyed) return
toast(failMsg)
}
}
)
}
private fun copySelectedImageToCache(uri: Uri): String? {
val extension = contentResolver.getType(uri)
?.let(MimeTypeMap.getSingleton()::getExtensionFromMimeType)
?.takeIf { it.isNotBlank() }
?: "jpg"
val imageDir = File(cacheDir, "selected_images")
if (!imageDir.exists() && !imageDir.mkdirs()) {
return null
}
val target = File(imageDir, "${System.currentTimeMillis()}.$extension")
return try {
val input = contentResolver.openInputStream(uri) ?: return null
input.use { source ->
target.outputStream().use { output -> source.copyTo(output) }
}
target.absolutePath.takeIf { target.length() > 0L }
?: run {
target.delete()
null
}
} catch (e: Exception) {
target.delete()
e.printStackTrace()
null
}
}
fun takePhoto() { fun takePhoto() {
try { try {
val openCameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE) val openCameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
@@ -408,6 +515,11 @@ class AddPetActivity : CKBaseActivity() {
}).show() }).show()
} }
companion object {
private const val REQUEST_CAMERA_PERMISSION = 1201
private const val REQUEST_AI_CAMERA_PERMISSION = 1202
}
fun uploadImage(path: String) { fun uploadImage(path: String) {
@@ -491,13 +603,10 @@ class AddPetActivity : CKBaseActivity() {
layoutItemImageBinding.imageDelete.visibility = View.GONE layoutItemImageBinding.imageDelete.visibility = View.GONE
} else { } else {
layoutItemImageBinding.image.scaleType = ImageView.ScaleType.CENTER_CROP layoutItemImageBinding.image.scaleType = ImageView.ScaleType.CENTER_CROP
layoutItemImageBinding.image.setImageBitmap( Glide.with(context)
TTUtils.getBitmap( .load(model.path?.let(::File))
model.path, .centerCrop()
200, .into(layoutItemImageBinding.image)
200
)
)
layoutItemImageBinding.imageDelete.visibility = View.VISIBLE layoutItemImageBinding.imageDelete.visibility = View.VISIBLE
layoutItemImageBinding.imageDelete.setOnClickListener { layoutItemImageBinding.imageDelete.setOnClickListener {

View File

@@ -3,27 +3,19 @@ package com.ck.ckcollar.app.ui.act.petmanager
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.Window
import android.view.WindowManager
import androidx.viewpager.widget.PagerAdapter import androidx.viewpager.widget.PagerAdapter
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.ck.ckcollar.app.R import com.ck.ckcollar.app.R
import com.ck.ckcollar.app.databinding.ActivityImageViewBinding import com.ck.ckcollar.app.databinding.ActivityImageViewBinding
import com.ck.ckcollar.app.databinding.ActivityWelcomeBinding
import com.ck.ckcollar.app.databinding.LayoutItemImageViewBinding import com.ck.ckcollar.app.databinding.LayoutItemImageViewBinding
import com.ck.ckcollar.app.databinding.LayoutItemWelcomeBinding
import com.ck.ckcollar.app.ui.act.login.LoginActivity
import com.ck.ckcollar.app.ui.act.welcome.PermisstionActivity
import com.ck.ckcollar.app.ui.base.CKBaseActivity import com.ck.ckcollar.app.ui.base.CKBaseActivity
import com.ck.ckcollar.app.utils.Const
import com.cyclone.shadowsocks.utils.PreferencesUtils
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.reflect.TypeToken import com.google.gson.reflect.TypeToken
import com.tt.kit.model.DataCollection
class ImageViewActivity : CKBaseActivity() { class ImageViewActivity : CKBaseActivity() {
override val useDarkStatusBarIcons: Boolean = false
lateinit var binding: ActivityImageViewBinding lateinit var binding: ActivityImageViewBinding
var views = mutableListOf<View>()
var data : List<String>? = null var data : List<String>? = null
var pos = 0 var pos = 0
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@@ -36,17 +28,9 @@ class ImageViewActivity : CKBaseActivity() {
} }
override fun initView() { override fun initView() {
for (i in data!!) {
var view = LayoutItemImageViewBinding.inflate(layoutInflater);
Glide.with(this)
.load(i)
.placeholder(R.mipmap.image_default)
.into(view.imageView)
views.add(view.root)
}
binding.viewPager.adapter = object : PagerAdapter() { binding.viewPager.adapter = object : PagerAdapter() {
override fun getCount(): Int { override fun getCount(): Int {
return views.size return data.orEmpty().size
} }
override fun isViewFromObject( override fun isViewFromObject(
@@ -57,12 +41,21 @@ class ImageViewActivity : CKBaseActivity() {
} }
override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
container.removeView(views.get(position)) container.removeView(`object` as View)
} }
override fun instantiateItem(container: ViewGroup, position: Int): Any { override fun instantiateItem(container: ViewGroup, position: Int): Any {
container.addView(views.get(position)) val itemBinding = LayoutItemImageViewBinding.inflate(
return views.get(position) layoutInflater,
container,
false
)
Glide.with(this@ImageViewActivity)
.load(data.orEmpty()[position])
.placeholder(R.mipmap.image_default)
.into(itemBinding.imageView)
container.addView(itemBinding.root)
return itemBinding.root
} }
} }

View File

@@ -2,6 +2,7 @@ package com.ck.ckcollar.app.ui.act.petmanager
import android.net.wifi.ScanResult import android.net.wifi.ScanResult
import android.os.Bundle import android.os.Bundle
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.PopupWindow import android.widget.PopupWindow
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
@@ -64,7 +65,7 @@ class PetManagerActivity : CKBaseActivity() {
} }
fun getData() { fun getData() {
//showProgeassDialog(getString(R.string.search)) showProgeassDialog(getString(R.string.search))
TTHttpClient.get(this, "宠物列表", TTRequestParam().apply { TTHttpClient.get(this, "宠物列表", TTRequestParam().apply {
add( add(
TTRequestData("pageNum", 1) TTRequestData("pageNum", 1)
@@ -81,6 +82,10 @@ class PetManagerActivity : CKBaseActivity() {
petAdapter.data = this@PetManagerActivity.data petAdapter.data = this@PetManagerActivity.data
petAdapter.notifyDataSetChanged() petAdapter.notifyDataSetChanged()
val isEmpty = this@PetManagerActivity.data.isEmpty()
binding.relNoresult.visibility = if (isEmpty) View.VISIBLE else View.GONE
binding.recyclerView.visibility = if (isEmpty) View.GONE else View.VISIBLE
} }
override fun onFailed(code: String, msg: String) { override fun onFailed(code: String, msg: String) {

View File

@@ -77,7 +77,10 @@ class ViewPetFileActivity: CKBaseActivity() {
} }
binding.btnViewPostion.setOnClickListener { binding.btnViewPostion.setOnClickListener {
if(homeModel?.collNum == null){
toast("请为您的爱宠绑定项圈")
return@setOnClickListener
}
getData2(model?.id.toString()) getData2(model?.id.toString())
} }
binding.btnAdreessDetails.setOnClickListener { binding.btnAdreessDetails.setOnClickListener {

View File

@@ -33,6 +33,7 @@ import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
class PointsActivity : CKLHBaseActionBarActivity() { class PointsActivity : CKLHBaseActionBarActivity() {
override val shouldRequestPermissionsOnCreate: Boolean = false
lateinit var binding: ActivityPointsBinding lateinit var binding: ActivityPointsBinding
var data = listOf<PointsModel.PointsRecordModel>() var data = listOf<PointsModel.PointsRecordModel>()

View File

@@ -109,6 +109,8 @@ class AccountCancellationActivity: CKBaseActivity() {
},object : ICallback{ },object : ICallback{
override fun onSuccess(data: String) { override fun onSuccess(data: String) {
PreferencesUtils.clear(this@AccountCancellationActivity) PreferencesUtils.clear(this@AccountCancellationActivity)
PreferencesUtils.putBoolean(this@AccountCancellationActivity, Const.FIRST, false)
CKApp.app.clearLoginState()
toActivityNewTaskClear(LoginActivity::class.java, DataCollection()) toActivityNewTaskClear(LoginActivity::class.java, DataCollection())
finish() finish()
} }

View File

@@ -168,7 +168,7 @@ class AddAddressActivity : CKBaseActivity() {
add(TTRequestData("provinceName",provinceName)) add(TTRequestData("provinceName",provinceName))
add(TTRequestData("cityName",cityName)) add(TTRequestData("cityName",cityName))
add(TTRequestData("areaName",areaName)) add(TTRequestData("areaName",areaName))
add(TTRequestData("detailAddress",binding.textDetailsAddress.text.toString())) add(TTRequestData("detailAddress",binding.textDetailsAddress.text.toString().trim()))
add(TTRequestData("postalCode","")) add(TTRequestData("postalCode",""))
add(TTRequestData("isDefault",check)) add(TTRequestData("isDefault",check))
add(TTRequestData("addressTag",tag)) add(TTRequestData("addressTag",tag))

View File

@@ -195,12 +195,12 @@ class EditAddressActivity : CKBaseActivity() {
} }
var param = TTRequestParam().apply { var param = TTRequestParam().apply {
add(TTRequestData("id", model?.id.toString())) add(TTRequestData("id", model?.id.toString()))
add(TTRequestData("receiverName", binding.textName.text.toString())) add(TTRequestData("receiverName", binding.textName.text.toString().trim()))
add(TTRequestData("receiverPhone", binding.textPhone.text.toString())) add(TTRequestData("receiverPhone", binding.textPhone.text.toString().trim()))
add(TTRequestData("provinceName", provinceName)) add(TTRequestData("provinceName", provinceName))
add(TTRequestData("cityName", cityName)) add(TTRequestData("cityName", cityName))
add(TTRequestData("areaName", areaName)) add(TTRequestData("areaName", areaName))
add(TTRequestData("detailAddress", binding.textDetailsAddress.text.toString())) add(TTRequestData("detailAddress", binding.textDetailsAddress.text.toString().trim()))
add(TTRequestData("postalCode", "")) add(TTRequestData("postalCode", ""))
add(TTRequestData("isDefault", check)) add(TTRequestData("isDefault", check))
add(TTRequestData("addressTag", tag)) add(TTRequestData("addressTag", tag))

View File

@@ -3,81 +3,74 @@ package com.ck.ckcollar.app.ui.act.setting
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import com.ck.ckcollar.app.CKApp
import com.ck.ckcollar.app.R import com.ck.ckcollar.app.R
import com.ck.ckcollar.app.config.Config
import com.ck.ckcollar.app.databinding.ActivitySettingBinding import com.ck.ckcollar.app.databinding.ActivitySettingBinding
import com.ck.ckcollar.app.ui.act.home.MainActivity
import com.ck.ckcollar.app.ui.act.login.AgreementActivity import com.ck.ckcollar.app.ui.act.login.AgreementActivity
import com.ck.ckcollar.app.ui.act.login.LoginActivity import com.ck.ckcollar.app.ui.act.login.LoginActivity
import com.ck.ckcollar.app.ui.base.CKBaseActivity import com.ck.ckcollar.app.ui.base.CKBaseActivity
import com.ck.ckcollar.app.ui.dialog.CKAlertDialog import com.ck.ckcollar.app.ui.dialog.CKAlertDialog
import com.ck.ckcollar.app.utils.Const
import com.cyclone.shadowsocks.utils.PreferencesUtils import com.cyclone.shadowsocks.utils.PreferencesUtils
import com.tt.kit.model.Data import com.tt.kit.model.Data
import com.tt.kit.model.DataCollection import com.tt.kit.model.DataCollection
class SettingActivity : CKBaseActivity(), View.OnClickListener { class SettingActivity : CKBaseActivity(), View.OnClickListener {
lateinit var binding: ActivitySettingBinding private lateinit var binding: ActivitySettingBinding
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
binding = ActivitySettingBinding.inflate(layoutInflater) binding = ActivitySettingBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setStatusBarColor(getColor(R.color.white))
setStatusBarColor(resources.getColor(R.color.white)) setActionBarColor(getColor(R.color.white))
setActionBarColor(resources.getColor(R.color.white))
setTitleText(getString(R.string.setting)) setTitleText(getString(R.string.setting))
} }
override fun initView() { override fun initView() {
binding.contentLoginPassword.setOnClickListener(this) binding.btnLogout.visibility = if (CKApp.app.isUserLoggedIn) View.VISIBLE else View.GONE
binding.contentPaymentPassword.setOnClickListener(this) listOf(binding.contentLoginPassword, binding.contentPaymentPassword, binding.contentAboutUs,
binding.contentAboutUs.setOnClickListener(this) binding.contentUserAgreement, binding.contentPrivacyAgreement, binding.contentShippingAddress,
binding.contentUserAgreement.setOnClickListener(this) binding.contentCancellation, binding.btnLogout).forEach { it.setOnClickListener(this) }
binding.contentPrivacyAgreement.setOnClickListener(this)
binding.contentShippingAddress.setOnClickListener(this)
binding.contentCancellation.setOnClickListener(this)
binding.btnLogout.setOnClickListener(this)
} }
override fun initData() {
} override fun initData() = Unit
override fun onClick(v: View?) { override fun onClick(v: View?) {
when (v?.id) { when (v?.id) {
R.id.contentLoginPassword->{ R.id.contentLoginPassword -> if (requireLogin()) toActivity(PasswordManagerActivity::class.java, DataCollection())
toActivity(PasswordManagerActivity::class.java, DataCollection()) R.id.contentPaymentPassword -> if (requireLogin()) toActivity(PayPasswordManagerActivity::class.java, DataCollection())
} R.id.contentAboutUs -> toActivity(AgreementActivity::class.java, DataCollection().apply { add(Data("title", getString(R.string.about_us))) })
R.id.contentPaymentPassword->{ R.id.contentUserAgreement -> toActivity(AgreementActivity::class.java, DataCollection().apply { add(Data("title", getString(R.string.user_agreement))) })
toActivity(PayPasswordManagerActivity::class.java, DataCollection()) R.id.contentPrivacyAgreement -> toActivity(SettingWebViewActivity::class.java, pageParams(Config.PRIVACY_POLICY, getString(R.string.privacy_agreement)))
R.id.contentShippingAddress -> if (requireLogin()) toActivity(AddressActivity::class.java, DataCollection().apply { add(Data("flag", "1")) })
} R.id.contentCancellation -> if (requireLogin()) toActivity(AccountCancellationActivity::class.java, DataCollection())
R.id.contentAboutUs->{ R.id.btnLogout -> CKAlertDialog(this, getString(R.string.logout), getString(R.string.logout_alert), object : CKAlertDialog.AlertClickListener {
toActivity(AgreementActivity::class.java, DataCollection().apply { add(Data("title","关于我们")) })
}
R.id.contentUserAgreement->{
toActivity(AgreementActivity::class.java, DataCollection().apply { add(Data("title","用户协议")) })
}
R.id.contentPrivacyAgreement->{
toActivity(AgreementActivity::class.java, DataCollection().apply { add(Data("title","隐私协议")) })
}
R.id.contentShippingAddress->{
toActivity(AddressActivity::class.java, DataCollection().apply { add(Data("flag","1"))
})
}
R.id.contentCancellation->{
toActivity(AccountCancellationActivity::class.java, DataCollection())
}
R.id.btnLogout->{
CKAlertDialog(this@SettingActivity,getString(R.string.logout),getString(R.string.logout_alert),object : CKAlertDialog.AlertClickListener{
override fun onBack(isConfirm: Boolean) { override fun onBack(isConfirm: Boolean) {
if (isConfirm) { if (isConfirm) {
PreferencesUtils.clear(this@SettingActivity) PreferencesUtils.putString(this@SettingActivity, Const.MESSAGE,"[]")
toActivityNewTaskClear(LoginActivity::class.java, DataCollection()) CKApp.app.clearLoginState()
startActivity(Intent(this@SettingActivity, MainActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
putExtra(MainActivity.EXTRA_SHOW_HOME, true)
})
finish() finish()
} }
} }
}).show() }).show()
}
}
} private fun pageParams(url: String, title: String) = DataCollection().apply {
} add(Data("url", url))
add(Data("title", title))
}
private fun requireLogin(): Boolean {
if (CKApp.app.isUserLoggedIn) return true
toActivity(LoginActivity::class.java, DataCollection())
return false
} }
} }

View File

@@ -0,0 +1,65 @@
package com.ck.ckcollar.app.ui.act.setting
import android.os.Bundle
import android.webkit.WebSettings
import android.webkit.WebView
import android.webkit.WebViewClient
import android.net.Uri
import com.ck.ckcollar.app.R
import com.ck.ckcollar.app.databinding.ActivitySettingWebViewBinding
import com.ck.ckcollar.app.ui.base.CKBaseActivity
/** Displays a setting document supplied by the caller. */
class SettingWebViewActivity : CKBaseActivity() {
private lateinit var binding: ActivitySettingWebViewBinding
override fun onCreate(savedInstanceState: Bundle?) {
binding = ActivitySettingWebViewBinding.inflate(layoutInflater)
setContentView(binding.root)
super.onCreate(savedInstanceState)
setActionBarColor(getColor(R.color.white))
setStatusBarColor(getColor(R.color.white))
}
override fun initView() {
binding.webView.settings.apply {
javaScriptEnabled = true; domStorageEnabled = true
useWideViewPort = true; loadWithOverviewMode = true
setSupportZoom(true); builtInZoomControls = true; displayZoomControls = false
layoutAlgorithm = WebSettings.LayoutAlgorithm.NARROW_COLUMNS
}
binding.webView.apply {
isFocusableInTouchMode = true
requestFocus()
webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
// Do this after the page's anchor/default restoration has run.
view?.post {
view.scrollTo(0, 0)
view.evaluateJavascript("window.scrollTo(0, 0);", null)
}
view?.postDelayed({ view.scrollTo(0, 0) }, 300)
}
}
}
}
override fun initData() {
val params = getReceiveParam()
setTitleText(params.get("title")?.stringValue?.toString().orEmpty())
val url = params.get("url")?.stringValue?.toString().orEmpty()
if (url.isNotEmpty()) {
// Fragment anchors (for example #a6 in the privacy URL) override the
// initial position, while this screen always starts at the document top.
val topUrl = runCatching { Uri.parse(url).buildUpon().fragment(null).build().toString() }
.getOrDefault(url)
binding.webView.loadUrl(topUrl)
}
}
override fun onDestroy() {
binding.webView.apply { stopLoading(); destroy() }
super.onDestroy()
}
}

View File

@@ -1,6 +1,7 @@
package com.ck.ckcollar.app.ui.act.shop package com.ck.ckcollar.app.ui.act.shop
import android.content.Context import android.content.Context
import android.content.pm.ApplicationInfo
import android.os.Bundle import android.os.Bundle
import android.text.TextUtils import android.text.TextUtils
import android.view.LayoutInflater import android.view.LayoutInflater
@@ -8,6 +9,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.alipay.sdk.app.EnvUtils
import com.alipay.sdk.app.PayTask import com.alipay.sdk.app.PayTask
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.ck.ckcollar.app.CKApp import com.ck.ckcollar.app.CKApp
@@ -21,6 +23,7 @@ import com.ck.ckcollar.app.model.AddressModel
import com.ck.ckcollar.app.model.ConfirmOrderModel import com.ck.ckcollar.app.model.ConfirmOrderModel
import com.ck.ckcollar.app.model.CreateOrderModel import com.ck.ckcollar.app.model.CreateOrderModel
import com.ck.ckcollar.app.model.MemberModel import com.ck.ckcollar.app.model.MemberModel
import com.ck.ckcollar.app.model.OrderPaymentModel
import com.ck.ckcollar.app.model.PayOrderModel import com.ck.ckcollar.app.model.PayOrderModel
import com.ck.ckcollar.app.model.PayPasswordStatus import com.ck.ckcollar.app.model.PayPasswordStatus
import com.ck.ckcollar.app.model.PayResult import com.ck.ckcollar.app.model.PayResult
@@ -28,20 +31,25 @@ import com.ck.ckcollar.app.model.ShopCarModel
import com.ck.ckcollar.app.model.ShopProductModel import com.ck.ckcollar.app.model.ShopProductModel
import com.ck.ckcollar.app.model.UserInfoModel import com.ck.ckcollar.app.model.UserInfoModel
import com.ck.ckcollar.app.ui.act.order.MyOrderActivity import com.ck.ckcollar.app.ui.act.order.MyOrderActivity
import com.ck.ckcollar.app.ui.act.balance.RechargeActivity
import com.ck.ckcollar.app.ui.act.setting.AddAddressActivity import com.ck.ckcollar.app.ui.act.setting.AddAddressActivity
import com.ck.ckcollar.app.ui.act.setting.AddressActivity import com.ck.ckcollar.app.ui.act.setting.AddressActivity
import com.ck.ckcollar.app.ui.act.setting.PayPsswordActivity import com.ck.ckcollar.app.ui.act.setting.PayPsswordActivity
import com.ck.ckcollar.app.ui.act.shop.ShopCarActivity.ShopCarAdapter import com.ck.ckcollar.app.ui.act.shop.ShopCarActivity.ShopCarAdapter
import com.ck.ckcollar.app.ui.base.CKBaseActivity import com.ck.ckcollar.app.ui.base.CKBaseActivity
import com.ck.ckcollar.app.utils.Const
import com.ck.ckcollar.app.utils.networkone.ICallback import com.ck.ckcollar.app.utils.networkone.ICallback
import com.ck.ckcollar.app.utils.networkone.TTHttpClient import com.ck.ckcollar.app.utils.networkone.TTHttpClient
import com.ck.ckcollar.app.utils.networkone.model.TTRequestData import com.ck.ckcollar.app.utils.networkone.model.TTRequestData
import com.ck.ckcollar.app.utils.networkone.model.TTRequestParam import com.ck.ckcollar.app.utils.networkone.model.TTRequestParam
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.reflect.TypeToken import com.google.gson.reflect.TypeToken
import com.tencent.mm.opensdk.modelpay.PayReq
import com.tencent.mm.opensdk.openapi.WXAPIFactory
import com.tt.kit.base.TTBaseActivity import com.tt.kit.base.TTBaseActivity
import com.tt.kit.model.Data import com.tt.kit.model.Data
import com.tt.kit.model.DataCollection import com.tt.kit.model.DataCollection
import com.tt.kit.utils.LiveDataBus
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -49,6 +57,7 @@ import kotlinx.coroutines.withContext
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONObject import org.json.JSONObject
import java.math.BigDecimal import java.math.BigDecimal
import java.math.RoundingMode
class OrderActivity : CKBaseActivity() { class OrderActivity : CKBaseActivity() {
@@ -62,7 +71,7 @@ class OrderActivity : CKBaseActivity() {
var memberModel: UserInfoModel? = null var memberModel: UserInfoModel? = null
var payType = "1" var payType = "0"
var selectBalance = false var selectBalance = false
var selectPoints = false var selectPoints = false
@@ -70,6 +79,10 @@ class OrderActivity : CKBaseActivity() {
lateinit var orderSource: String lateinit var orderSource: String
var flag = 0 var flag = 0
private var currentOrderId = 0
private var isCancellingOrder = false
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
binding = ActivityOrderBinding.inflate(layoutInflater) binding = ActivityOrderBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
@@ -78,7 +91,20 @@ class OrderActivity : CKBaseActivity() {
setTitleText(getString(R.string.confirm_order)) setTitleText(getString(R.string.confirm_order))
} }
override fun onResume() {
super.onResume()
var abc = 0;
}
override fun initView() { override fun initView() {
LiveDataBus.get().with(RechargeActivity.WX_PAY_RESULT, Int::class.java).observe(this) { result ->
if (result == 0) {
handlePaymentSuccess()
} else {
handlePaymentFailed(result == -2)
}
}
productAdapter = productAdapter =
ProductAdapter(this@OrderActivity, productDatas, object : OnItemClickListenner { ProductAdapter(this@OrderActivity, productDatas, object : OnItemClickListenner {
override fun onClick(pos: Int, model: Any) { override fun onClick(pos: Int, model: Any) {
@@ -95,7 +121,11 @@ class OrderActivity : CKBaseActivity() {
binding.btnWX.setOnClickListener(payClick) binding.btnWX.setOnClickListener(payClick)
binding.btnBalance.setOnClickListener { binding.btnBalance.setOnClickListener {
if (memberModel?.balance == 0.0){ if (clearBalanceIfPointsSufficient()) {
toast("积分足够无需使用余额")
return@setOnClickListener
}
if ((memberModel?.balance ?: 0.0) <= 0.0){
toast(getString(R.string.balance_over)) toast(getString(R.string.balance_over))
return@setOnClickListener return@setOnClickListener
} }
@@ -106,14 +136,22 @@ class OrderActivity : CKBaseActivity() {
}else{ }else{
binding.image3.setImageResource(R.mipmap.image_address_check_narmal) binding.image3.setImageResource(R.mipmap.image_address_check_narmal)
} }
clearExternalPaymentIfNotNeeded()
} }
binding.btnPoints.setOnClickListener { binding.btnPoints.setOnClickListener {
if ((memberModel?.points ?: 0.0) <= 0.0) {
toast(getString(R.string.points_over))
return@setOnClickListener
}
selectPoints = !selectPoints selectPoints = !selectPoints
if (selectPoints){ if (selectPoints){
binding.image4.setImageResource(R.mipmap.image_address_check_select) binding.image4.setImageResource(R.mipmap.image_address_check_select)
}else{ }else{
binding.image4.setImageResource(R.mipmap.image_address_check_narmal) binding.image4.setImageResource(R.mipmap.image_address_check_narmal)
} }
clearBalanceIfPointsSufficient()
clearExternalPaymentIfNotNeeded()
} }
binding.contentAddress.setOnClickListener { binding.contentAddress.setOnClickListener {
@@ -123,7 +161,7 @@ class OrderActivity : CKBaseActivity() {
} }
binding.btnBuyNow.setOnClickListener { binding.btnBuyNow.setOnClickListener {
if (selectBalance){ if (selectBalance && !canPointsCoverPayAmount()){
getPayPassword() getPayPassword()
}else{ }else{
order("") order("")
@@ -287,38 +325,54 @@ class OrderActivity : CKBaseActivity() {
param.put("buyerNote", "") param.put("buyerNote", "")
param.put("items", items) param.put("items", items)
param.put("payPassword", payPassword) param.put("payPassword", payPassword)
param.put("orderId", model.orderId)
showProgeassDialog(getString(R.string.order)) showProgeassDialog(getString(R.string.order))
TTHttpClient.postJson(this, "下单", param.toString(), object : ICallback { TTHttpClient.postJson(this, "下单", param.toString(), object : ICallback {
override fun onSuccess(data: String) { override fun onSuccess(data: String) {
var model = Gson().fromJson<PayOrderModel>(data, PayOrderModel::class.java) val paymentModel = Gson().fromJson(data, OrderPaymentModel::class.java)
currentOrderId = paymentModel.orderId
if ("0".equals(this@OrderActivity.payType)) { if ("0".equals(this@OrderActivity.payType)) {
//微信 val weChatPayParams = paymentModel.wxMap
if (weChatPayParams == null || !weChatPayParams.isJsonObject) {
hiddenProgeassDialog()
toast("微信支付参数格式错误")
return
}
wxPay(Gson().fromJson(weChatPayParams, PayOrderModel::class.java))
}else if ("1".equals(this@OrderActivity.payType)) { }else if ("1".equals(this@OrderActivity.payType)) {
if (TextUtils.isEmpty(model.orderStr)){ val aliPayOrderStr = paymentModel.orderStr
?.takeIf { it.isJsonPrimitive && it.asJsonPrimitive.isString }
?.asString
if (TextUtils.isEmpty(aliPayOrderStr)){
toActivity(OrderSuccessActivity::class.java, DataCollection()) toActivity(OrderSuccessActivity::class.java, DataCollection())
finish() finish()
}else{ }else{
aliPay(model.orderStr!!) aliPay(aliPayOrderStr!!)
} }
}else{ }else{
toast(getString(R.string.order_success)) toast(getString(R.string.order_success))
toActivity(OrderSuccessActivity::class.java, DataCollection()) toActivity(OrderSuccessActivity::class.java, DataCollection())
finish() finish()
} }
} }
override fun onFailed(code: String, msg: String) { override fun onFailed(code: String, msg: String) {
toast(msg) toast(msg)
if (msg.indexOf("不足")>=0){ }
toActivity(
MyOrderActivity::class.java, override fun onFailed(code: String, msg: String, data: String) {
DataCollection().apply { add(Data("pos", "1")) }) onFailed(code, msg)
finish() //原有【不足】的字符串判断条件
if (code == "502") {
val orderId = JSONObject(data).optInt("orderId")
if (orderId > 0) {
model.orderId = orderId
}
} }
} }
}) })
@@ -327,6 +381,10 @@ class OrderActivity : CKBaseActivity() {
fun aliPay(orderStr: String) { fun aliPay(orderStr: String) {
GlobalScope.launch(Dispatchers.IO) { GlobalScope.launch(Dispatchers.IO) {
// [支付宝沙箱测试] 仅 Debug 包启用Release 包继续使用正式环境。
if (applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE != 0) {
// EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX)
}
val alipay = PayTask(this@OrderActivity) val alipay = PayTask(this@OrderActivity)
val result = alipay.payV2(orderStr, true) val result = alipay.payV2(orderStr, true)
@@ -337,19 +395,110 @@ class OrderActivity : CKBaseActivity() {
// 判断resultStatus 为9000则代表支付成功 // 判断resultStatus 为9000则代表支付成功
if (TextUtils.equals(resultStatus, "9000")) { if (TextUtils.equals(resultStatus, "9000")) {
// 该笔订单是否真实支付成功,需要依赖服务端的异步通知。 // 该笔订单是否真实支付成功,需要依赖服务端的异步通知。
handlePaymentSuccess()
} else {
handlePaymentFailed(TextUtils.equals(resultStatus, "6001"))
}
}
}
}
private fun wxPay(model: PayOrderModel) {
val requiredValues = listOf(
model.appId,
model.partnerId,
model.prepayId,
model.packageVal,
model.nonceStr,
model.timeStamp,
model.paySign
)
if (requiredValues.any { it.isNullOrBlank() }) {
hiddenProgeassDialog()
toast("微信支付参数不完整,请检查商户号等支付参数")
return
}
if (model.appId != Const.WX_APP_ID) {
hiddenProgeassDialog()
toast("微信支付 AppID 不匹配")
return
}
val api = WXAPIFactory.createWXAPI(this, Const.WX_APP_ID, true)
api.registerApp(Const.WX_APP_ID)
if (!api.isWXAppInstalled) {
hiddenProgeassDialog()
toast("请先安装微信")
return
}
val request = PayReq().apply {
appId = model.appId
partnerId = model.partnerId
prepayId = model.prepayId
packageValue = model.packageVal
nonceStr = model.nonceStr
timeStamp = model.timeStamp
sign = model.paySign
extData = model.orderNo
}
hiddenProgeassDialog()
if (!api.sendReq(request)) {
toast("微信支付拉起失败")
}
}
private fun handlePaymentSuccess() {
toast(getString(R.string.payment_success)) toast(getString(R.string.payment_success))
toActivity(OrderSuccessActivity::class.java, DataCollection()) toActivity(OrderSuccessActivity::class.java, DataCollection())
finish() finish()
} else { }
private fun handlePaymentFailed(cancelled: Boolean) {
if (cancelled) {
cancelPendingOrder()
return
}
toast(getString(R.string.payment_faild)) toast(getString(R.string.payment_faild))
openPendingOrderList()
}
private fun cancelPendingOrder() {
if (isCancellingOrder) return
if (currentOrderId <= 0) {
toast(getString(R.string.payment_faild))
openPendingOrderList()
return
}
isCancellingOrder = true
showProgeassDialog(getString(R.string.cancel))
TTHttpClient.post(this, "取消待支付订单", TTRequestParam().apply {
add(TTRequestData("orderId", currentOrderId))
}, object : ICallback {
override fun onSuccess(data: String) {
hiddenProgeassDialog()
toast(getString(R.string.cancel_pay_cussess))
openPendingOrderList()
}
override fun onFailed(code: String, msg: String) {
hiddenProgeassDialog()
toast(msg)
openPendingOrderList()
}
})
}
private fun openPendingOrderList() {
toActivity( toActivity(
MyOrderActivity::class.java, MyOrderActivity::class.java,
DataCollection().apply { add(Data("pos", "1")) }) DataCollection().apply { add(Data("pos", "1")) }
)
finish() finish()
} }
}
}
}
fun getMemberInfo() { fun getMemberInfo() {
TTHttpClient.get(this, "个人资料", TTRequestParam(), object : ICallback { TTHttpClient.get(this, "个人资料", TTRequestParam(), object : ICallback {
@@ -393,16 +542,18 @@ class OrderActivity : CKBaseActivity() {
fun showPayBottomView(){ fun showPayBottomView(){
var showBalance = model.payAmount var showBalance = BigDecimal.valueOf(model.payAmount).setScale(2, RoundingMode.HALF_UP)
if (selectPoints){ if (selectPoints){
CKApp.app.userInfo?.intoAmounts?.let { calculatePointsDeduction()?.let { pointsDeduction ->
showBalance = showBalance - BigDecimal(memberModel?.points!!).multiply( showBalance = showBalance.subtract(pointsDeduction)
BigDecimal(memberModel!!.intoAmounts!!)).setScale(2).toDouble() .max(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP))
if (showBalance < 0.0){
showBalance = 0.00
}
} }
} }
val userBalance = BigDecimal.valueOf(memberModel?.balance ?: 0.0)
.setScale(2, RoundingMode.HALF_UP)
showBalance = showBalance.min(userBalance)
var passwordBottomFragment = PayPasswordBottomFragment(showBalance.toString(), "余额",object : PayPasswordBottomFragment.PasswordCallBack{ var passwordBottomFragment = PayPasswordBottomFragment(showBalance.toString(), "余额",object : PayPasswordBottomFragment.PasswordCallBack{
override fun callBack(password: String) { override fun callBack(password: String) {
@@ -413,8 +564,64 @@ class OrderActivity : CKBaseActivity() {
passwordBottomFragment.show(supportFragmentManager, "PayPasswordBottomFragment") passwordBottomFragment.show(supportFragmentManager, "PayPasswordBottomFragment")
} }
private fun canPointsCoverPayAmount(): Boolean {
if (!selectPoints) return false
val pointsDeduction = calculatePointsDeduction() ?: return false
val payAmount = BigDecimal.valueOf(model.payAmount).setScale(2, RoundingMode.HALF_UP)
return pointsDeduction >= payAmount
}
private fun clearBalanceIfPointsSufficient(): Boolean {
if (!canPointsCoverPayAmount()) return false
selectBalance = false
binding.image3.setImageResource(R.mipmap.image_address_check_narmal)
return true
}
private fun calculatePointsDeduction(): BigDecimal? {
val member = memberModel ?: return null
val intoAmounts = member.intoAmounts?.toBigDecimalOrNull() ?: return null
return BigDecimal.valueOf(member.points)
.multiply(intoAmounts)
.setScale(2, RoundingMode.HALF_UP)
}
private fun isInternalPaymentSufficient(): Boolean {
var internalAmount = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP)
if (selectBalance) {
internalAmount = internalAmount.add(
BigDecimal.valueOf(memberModel?.balance ?: 0.0)
.setScale(2, RoundingMode.HALF_UP)
)
}
if (selectPoints) {
internalAmount = internalAmount.add(
calculatePointsDeduction() ?: BigDecimal.ZERO
)
}
val payAmount = BigDecimal.valueOf(model.payAmount)
.setScale(2, RoundingMode.HALF_UP)
return internalAmount >= payAmount
}
private fun clearExternalPaymentIfNotNeeded() {
if (!isInternalPaymentSufficient()) return
payType = ""
binding.image1.setImageResource(R.mipmap.image_address_check_narmal)
binding.image2.setImageResource(R.mipmap.image_address_check_narmal)
}
var payClick = object : View.OnClickListener { var payClick = object : View.OnClickListener {
override fun onClick(v: View?) { override fun onClick(v: View?) {
if (isInternalPaymentSufficient()) {
clearExternalPaymentIfNotNeeded()
toast("当前支付方式无需使用三方支付")
return
}
binding.image1.setImageResource(R.mipmap.image_address_check_narmal) binding.image1.setImageResource(R.mipmap.image_address_check_narmal)
binding.image2.setImageResource(R.mipmap.image_address_check_narmal) binding.image2.setImageResource(R.mipmap.image_address_check_narmal)
when (v?.id) { when (v?.id) {

View File

@@ -13,6 +13,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.load.resource.bitmap.RoundedCorners import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.RequestOptions
import com.ck.ckcollar.app.CKApp
import com.ck.ckcollar.app.R import com.ck.ckcollar.app.R
import com.ck.ckcollar.app.action.ActionCode import com.ck.ckcollar.app.action.ActionCode
import com.ck.ckcollar.app.databinding.ActivityProductDetailsBinding import com.ck.ckcollar.app.databinding.ActivityProductDetailsBinding
@@ -23,6 +24,7 @@ import com.ck.ckcollar.app.ui.act.customer.PeopleCustomerActivity
import com.ck.ckcollar.app.ui.act.customer.ShopCustomerActivity import com.ck.ckcollar.app.ui.act.customer.ShopCustomerActivity
import com.ck.ckcollar.app.ui.act.home.fragment.HomeFragment import com.ck.ckcollar.app.ui.act.home.fragment.HomeFragment
import com.ck.ckcollar.app.ui.act.home.fragment.HomeFragment.ImageAdapter import com.ck.ckcollar.app.ui.act.home.fragment.HomeFragment.ImageAdapter
import com.ck.ckcollar.app.ui.act.login.LoginActivity
import com.ck.ckcollar.app.ui.act.petmanager.ImageViewActivity import com.ck.ckcollar.app.ui.act.petmanager.ImageViewActivity
import com.ck.ckcollar.app.ui.base.CKBaseActivity import com.ck.ckcollar.app.ui.base.CKBaseActivity
import com.ck.ckcollar.app.ui.base.CKLHBaseActionBarActivity import com.ck.ckcollar.app.ui.base.CKLHBaseActionBarActivity
@@ -63,20 +65,30 @@ class ProductDetailsActivity : CKBaseActivity() {
setupWebView(binding.textContent) setupWebView(binding.textContent)
binding.btnAddCar.setOnClickListener { binding.btnAddCar.setOnClickListener {
if (!requireLogin()) return@setOnClickListener
showProductTypeFragment() showProductTypeFragment()
} }
binding.btnBuyNow.setOnClickListener { binding.btnBuyNow.setOnClickListener {
if (!requireLogin()) return@setOnClickListener
showProductTypeFragment() showProductTypeFragment()
} }
binding.contentShopCar.setOnClickListener { binding.contentShopCar.setOnClickListener {
if (!requireLogin()) return@setOnClickListener
toActivity(ShopCarActivity::class.java, DataCollection()) toActivity(ShopCarActivity::class.java, DataCollection())
} }
binding.contentCustomer.setOnClickListener { binding.contentCustomer.setOnClickListener {
if (!requireLogin()) return@setOnClickListener
toActivity(PeopleCustomerActivity::class.java, DataCollection().apply { add(Data("chatType","1")) }) toActivity(PeopleCustomerActivity::class.java, DataCollection().apply { add(Data("chatType","1")) })
} }
} }
private fun requireLogin(): Boolean {
if (CKApp.app.isUserLoggedIn) return true
toActivity(LoginActivity::class.java, DataCollection())
return false
}
override fun initData() { override fun initData() {
model = Gson().fromJson<ShopProductModel.ProductModel>(getReceiveParam().get("data")!!.stringValue, model = Gson().fromJson<ShopProductModel.ProductModel>(getReceiveParam().get("data")!!.stringValue,
ShopProductModel.ProductModel::class.java) ShopProductModel.ProductModel::class.java)
@@ -148,7 +160,7 @@ class ProductDetailsActivity : CKBaseActivity() {
ViewGroup.LayoutParams.MATCH_PARENT ViewGroup.LayoutParams.MATCH_PARENT
) )
) )
imageView.setScaleType(ImageView.ScaleType.FIT_XY) imageView.setScaleType(ImageView.ScaleType.CENTER_CROP)
return BannerViewHolder(imageView) return BannerViewHolder(imageView)
} }

View File

@@ -4,6 +4,7 @@ import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.text.TextUtils import android.text.TextUtils
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
@@ -91,6 +92,10 @@ class ShopCarActivity : CKLHBaseActionBarActivity() {
binding.checkbox.setOnClickListener { binding.checkbox.setOnClickListener {
if (productDatas.isEmpty()) {
toast(getString(R.string.shop_car_empty))
return@setOnClickListener
}
selectAll = !selectAll selectAll = !selectAll
if (selectAll){ if (selectAll){
@@ -154,6 +159,11 @@ class ShopCarActivity : CKLHBaseActionBarActivity() {
override fun rightButton1OnClick() { override fun rightButton1OnClick() {
if (productDatas.isEmpty()) {
toast(getString(R.string.shop_car_empty))
return
}
isShowDelete = !isShowDelete isShowDelete = !isShowDelete
if (isShowDelete){ if (isShowDelete){
@@ -214,6 +224,7 @@ class ShopCarActivity : CKLHBaseActionBarActivity() {
}) })
} }
fun getData(){ fun getData(){
showProgeassDialog()
TTHttpClient.get(this,"购物车列表", TTRequestParam(),object : ICallback{ TTHttpClient.get(this,"购物车列表", TTRequestParam(),object : ICallback{
override fun onSuccess(data: String) { override fun onSuccess(data: String) {
this@ShopCarActivity.productDatas = Gson().fromJson<List<ShopCarModel>>(data, object : TypeToken<List<ShopCarModel>>(){}.type) this@ShopCarActivity.productDatas = Gson().fromJson<List<ShopCarModel>>(data, object : TypeToken<List<ShopCarModel>>(){}.type)
@@ -221,6 +232,10 @@ class ShopCarActivity : CKLHBaseActionBarActivity() {
shopCarAdapter.data = this@ShopCarActivity.productDatas shopCarAdapter.data = this@ShopCarActivity.productDatas
shopCarAdapter.notifyDataSetChanged() shopCarAdapter.notifyDataSetChanged()
val isEmpty = this@ShopCarActivity.productDatas.isEmpty()
binding.relNoresult.visibility = if (isEmpty) View.VISIBLE else View.GONE
binding.recyclerView.visibility = if (isEmpty) View.GONE else View.VISIBLE
var flag = true var flag = true
for (model in productDatas){ for (model in productDatas){
if ("0".equals(model.selected)){ if ("0".equals(model.selected)){
@@ -242,7 +257,7 @@ class ShopCarActivity : CKLHBaseActionBarActivity() {
} }
override fun onFailed(code: String, msg: String) { override fun onFailed(code: String, msg: String) {
toast(msg)
} }
}) })
} }
@@ -296,14 +311,15 @@ class ShopCarActivity : CKLHBaseActionBarActivity() {
} }
fun sendSelectAll(select : String){ fun sendSelectAll(select : String){
showProgeassDialog()
TTHttpClient.putJson(this,"购物车全部选中", TTRequestParam().apply { add(TTRequestData("selected",select)) },object : ICallback{ TTHttpClient.putJson(this,"购物车全部选中", TTRequestParam().apply { add(TTRequestData("selected",select)) },object : ICallback{
override fun onSuccess(data: String) { override fun onSuccess(data: String) {
hiddenProgeassDialog()
getData() getData()
} }
override fun onFailed(code: String, msg: String) { override fun onFailed(code: String, msg: String) {
hiddenProgeassDialog()
toast(msg) toast(msg)
getData() getData()
} }

View File

@@ -3,6 +3,7 @@ package com.ck.ckcollar.app.ui.act.shop
import android.content.Context import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
@@ -33,6 +34,8 @@ import com.tt.kit.model.DataCollection
import com.tt.kit.utils.KeyboardUtils import com.tt.kit.utils.KeyboardUtils
class TypeActivity : CKLHBaseActionBarActivity() { class TypeActivity : CKLHBaseActionBarActivity() {
override val shouldRequestPermissionsOnCreate: Boolean = false
lateinit var binding: ActivityShopTypeBinding lateinit var binding: ActivityShopTypeBinding
lateinit var productAdapter: ProductAdapter lateinit var productAdapter: ProductAdapter
@@ -86,6 +89,7 @@ class TypeActivity : CKLHBaseActionBarActivity() {
fun getData() { fun getData() {
showProgeassDialog()
TTHttpClient.get(this, "商品列表", TTRequestParam().apply { TTHttpClient.get(this, "商品列表", TTRequestParam().apply {
add( add(
TTRequestData("pageNum", page) TTRequestData("pageNum", page)
@@ -107,12 +111,18 @@ class TypeActivity : CKLHBaseActionBarActivity() {
productAdapter.data = productDatas productAdapter.data = productDatas
productAdapter.notifyDataSetChanged() productAdapter.notifyDataSetChanged()
val isEmpty = productDatas.isEmpty()
binding.relNoresult.visibility = if (isEmpty) View.VISIBLE else View.GONE
binding.recyclerView.visibility = if (isEmpty) View.GONE else View.VISIBLE
binding.refreshLayout.finishLoadMore(true) binding.refreshLayout.finishLoadMore(true)
binding.refreshLayout.finishRefresh() binding.refreshLayout.finishRefresh()
} }
override fun onFailed(code: String, msg: String) { override fun onFailed(code: String, msg: String) {
binding.refreshLayout.finishLoadMore(true) binding.refreshLayout.finishLoadMore(false)
binding.refreshLayout.finishRefresh()
toast(msg)
} }
}) })

View File

@@ -1,5 +1,6 @@
package com.ck.ckcollar.app.ui.act.user package com.ck.ckcollar.app.ui.act.user
import android.Manifest
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
@@ -20,12 +21,12 @@ import com.ck.ckcollar.app.model.UserInfoModel
import com.ck.ckcollar.app.ui.act.home.MainActivity import com.ck.ckcollar.app.ui.act.home.MainActivity
import com.ck.ckcollar.app.ui.act.login.BoundPhoneActivity import com.ck.ckcollar.app.ui.act.login.BoundPhoneActivity
import com.ck.ckcollar.app.ui.base.CKBaseActivity import com.ck.ckcollar.app.ui.base.CKBaseActivity
import com.ck.ckcollar.app.ui.dialog.CKAlertDialog
import com.ck.ckcollar.app.ui.dialog.CKEditDialog import com.ck.ckcollar.app.ui.dialog.CKEditDialog
import com.ck.ckcollar.app.ui.dialog.CKEditNameDialog import com.ck.ckcollar.app.ui.dialog.CKEditNameDialog
import com.ck.ckcollar.app.ui.dialog.CKEditPhoneDialog import com.ck.ckcollar.app.ui.dialog.CKEditPhoneDialog
import com.ck.ckcollar.app.ui.dialog.CKPhotoDialog import com.ck.ckcollar.app.ui.dialog.CKPhotoDialog
import com.ck.ckcollar.app.utils.Const import com.ck.ckcollar.app.utils.Const
import com.ck.ckcollar.app.utils.IDCardValidate
import com.ck.ckcollar.app.utils.networkone.ICallback import com.ck.ckcollar.app.utils.networkone.ICallback
import com.ck.ckcollar.app.utils.networkone.TTHttpClient import com.ck.ckcollar.app.utils.networkone.TTHttpClient
import com.ck.ckcollar.app.utils.networkone.model.TTRequestData import com.ck.ckcollar.app.utils.networkone.model.TTRequestData
@@ -55,7 +56,7 @@ class UserInfoActivity: CKBaseActivity() {
api = WXAPIFactory.createWXAPI(this, Const.WX_APP_ID) api = WXAPIFactory.createWXAPI(this, Const.WX_APP_ID)
CKApp.app.wxJump = 1 CKApp.app.wxJump = 1
checkAppPermissions() // checkAppPermissions()
setStatusBarColor(resources.getColor(R.color.white)) setStatusBarColor(resources.getColor(R.color.white))
setActionBarColor(resources.getColor(R.color.white)) setActionBarColor(resources.getColor(R.color.white))
@@ -86,7 +87,7 @@ class UserInfoActivity: CKBaseActivity() {
binding.textPhone.setOnClickListener { binding.textPhone.setOnClickListener {
CKEditPhoneDialog( CKEditPhoneDialog(
this@UserInfoActivity, this@UserInfoActivity,
getString(R.string.bind_phone), getString(R.string.modify_phone_number),
object : CKEditPhoneDialog.AlertClickListener { object : CKEditPhoneDialog.AlertClickListener {
override fun onBack(text: String) { override fun onBack(text: String) {
binding.textPhone.text = text binding.textPhone.text = text
@@ -99,7 +100,12 @@ class UserInfoActivity: CKBaseActivity() {
binding.textIdCard.setOnClickListener { binding.textIdCard.setOnClickListener {
CKEditDialog(this@UserInfoActivity,getString(R.string.id_card),binding.textIdCard.text.toString(),object : CKEditDialog.AlertClickListener{ CKEditDialog(this@UserInfoActivity,getString(R.string.id_card),binding.textIdCard.text.toString(),object : CKEditDialog.AlertClickListener{
override fun onBack(text: String) { override fun onBack(text: String) {
binding.textIdCard.text = text val idCard = text.trim().uppercase()
if (!IDCardValidate.validateEffective(idCard)) {
toast("请输入正确的身份证号码")
return
}
binding.textIdCard.text = idCard
save() save()
} }
}).show() }).show()
@@ -111,16 +117,10 @@ class UserInfoActivity: CKBaseActivity() {
override fun onBack(mark: Int, position: Int) { override fun onBack(mark: Int, position: Int) {
try { try {
if (mark == 0){ if (mark == 0){
if (!checkCameraPermissions()){ getPermissionRequst(
CKAlertDialog(this@UserInfoActivity,getString(R.string.alert),getString(R.string.camera_alert),object : CKAlertDialog.AlertClickListener{ Manifest.permission.CAMERA,
override fun onBack(isConfirm: Boolean) { REQUEST_CAMERA_PERMISSION
TODO("Not yet implemented") )
}
}).show()
return
}
takePhoto()
}else{ }else{
//相册 //相册
val i = Intent( val i = Intent(
@@ -148,6 +148,12 @@ class UserInfoActivity: CKBaseActivity() {
} }
} }
override fun onPermissionsGranted(requestCode: Int, permissions: Array<String>) {
if (requestCode == REQUEST_CAMERA_PERMISSION) {
takePhoto()
}
}
override fun onNewIntent(intent: Intent) { override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent) super.onNewIntent(intent)
@@ -242,6 +248,10 @@ class UserInfoActivity: CKBaseActivity() {
} }
companion object {
private const val REQUEST_CAMERA_PERMISSION = 1101
}
override fun initData() { override fun initData() {
binding.textNick.text= CKApp.app.userInfo?.custName binding.textNick.text= CKApp.app.userInfo?.custName

View File

@@ -4,11 +4,27 @@ import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.os.Message import android.os.Message
import android.text.TextUtils import android.app.AlertDialog
import android.graphics.Color
import android.graphics.drawable.GradientDrawable
import android.text.SpannableString
import android.text.Spanned
import android.text.method.LinkMovementMethod
import android.text.style.ClickableSpan
import android.view.View
import android.view.Gravity
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.ScrollView
import com.ck.ckcollar.app.CKApp import com.ck.ckcollar.app.CKApp
import com.ck.ckcollar.app.R
import com.ck.ckcollar.app.databinding.ActivityIndexBinding import com.ck.ckcollar.app.databinding.ActivityIndexBinding
import com.ck.ckcollar.app.ui.act.home.MainActivity import com.ck.ckcollar.app.ui.act.home.MainActivity
import com.ck.ckcollar.app.ui.act.login.LoginActivity import com.ck.ckcollar.app.ui.act.login.AgreementActivity
import com.ck.ckcollar.app.ui.act.setting.SettingWebViewActivity
import com.ck.ckcollar.app.config.Config
import com.ck.ckcollar.app.ui.base.CKBaseActivity import com.ck.ckcollar.app.ui.base.CKBaseActivity
import com.ck.ckcollar.app.utils.Const import com.ck.ckcollar.app.utils.Const
import com.cyclone.shadowsocks.utils.PreferencesUtils import com.cyclone.shadowsocks.utils.PreferencesUtils
@@ -25,20 +41,90 @@ class IndexActivity : CKBaseActivity() {
} }
var handler = object : Handler(Looper.getMainLooper()){ var handler = object : Handler(Looper.getMainLooper()){
override fun handleMessage(msg: Message) { override fun handleMessage(msg: Message) {
if (TextUtils.isEmpty(CKApp.app.token)){ continueAfterAgreement()
var isFirst = PreferencesUtils.getBolean(this@IndexActivity, Const.FIRST,true) as Boolean
if (isFirst){
toActivity(WelcomeActivity::class.java, DataCollection())
}else{
toActivity(LoginActivity::class.java, DataCollection())
} }
}else{
toActivity(MainActivity::class.java, DataCollection())
} }
private fun continueAfterAgreement() {
val agreed = PreferencesUtils.getBolean(this, Const.AGREEMENT_CHECK, false) as Boolean
if (!agreed) {
showUserNotice()
return
}
val isFirst = PreferencesUtils.getBolean(this, Const.FIRST, true) as Boolean
toActivity(if (isFirst) WelcomeActivity::class.java else MainActivity::class.java, DataCollection())
finish() finish()
} }
private fun showUserNotice() {
fun dp(value: Int) = (value * resources.displayMetrics.density).toInt()
val title = TextView(this).apply {
text = "用户须知"
setTextColor(Color.rgb(35, 39, 55))
textSize = 20f
gravity = Gravity.CENTER
setTypeface(typeface, android.graphics.Typeface.BOLD)
}
val content = TextView(this).apply {
setTextColor(Color.rgb(95, 99, 115))
textSize = 14f
setLineSpacing(0f, 1.35f)
movementMethod = LinkMovementMethod.getInstance()
val text = "感谢您使用宠盾!我们非常重视您的个人信息和隐私保护。请阅读并同意《用户协议》和《隐私协议》后继续使用。\n\n1. 为提供宠物管理、设备连接、消息通知和 AI 识别等服务,我们可能会收集必要的账号、设备及使用信息。\n\n2. 在您使用拍照、扫码、地图定位、蓝牙或相册等功能时,我们会在获得授权后申请相应权限;您可以随时在系统设置中关闭权限,但可能无法使用对应功能。\n\n3. 我们会采取合理的安全措施保护您的信息,不会将信息用于协议约定以外的用途,也不会向无关方出售或出租您的信息。\n\n4. 为保障服务稳定运行,部分功能可能由第三方服务提供商协助完成,我们会要求其按照法律法规和隐私政策保护您的信息。\n\n5. 当协议内容或服务发生重要变化时,我们会通过弹窗或其他适当方式提醒您。您可以通过应用内相关入口再次查看完整协议。"
val spannable = SpannableString(text)
val userStart = text.indexOf("《用户协议》")
val privacyStart = text.indexOf("《隐私协议》")
spannable.setSpan(object : ClickableSpan() {
override fun onClick(widget: View) = toActivity(AgreementActivity::class.java, DataCollection().apply { add(com.tt.kit.model.Data("title", getString(R.string.user_agreement))) })
}, userStart, userStart + 6, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
spannable.setSpan(object : ClickableSpan() {
override fun onClick(widget: View) = toActivity(SettingWebViewActivity::class.java, DataCollection().apply {
add(com.tt.kit.model.Data("url", Config.PRIVACY_POLICY)); add(com.tt.kit.model.Data("title", getString(R.string.privacy_agreement)))
})
}, privacyStart, privacyStart + 6, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
setText(spannable)
}
val contentScroll = ScrollView(this).apply {
isFillViewport = true
isVerticalScrollBarEnabled = false
addView(content, ViewGroup.LayoutParams(-1, -2))
}
lateinit var dialog: AlertDialog
val buttons = LinearLayout(this).apply {
orientation = LinearLayout.HORIZONTAL
gravity = Gravity.CENTER
}
fun action(text: String, backgroundColor: Int, textColor: Int, onClick: () -> Unit) = TextView(this).apply {
this.text = text; gravity = Gravity.CENTER; setTextColor(textColor); textSize = 15f
setTypeface(typeface, android.graphics.Typeface.BOLD); setPadding(0, dp(13), 0, dp(13))
background = GradientDrawable().apply { setColor(backgroundColor); cornerRadius = dp(10).toFloat() }
setOnClickListener { onClick() }
}
val rejectButton = action("不同意", Color.rgb(245, 246, 250), Color.rgb(35, 39, 55), {
dialog.dismiss(); finishAndRemoveTask()
})
val agreeButton = action("同意", getColor2(R.attr.buttonColor), Color.WHITE) {
PreferencesUtils.putBoolean(this@IndexActivity, Const.AGREEMENT_CHECK, true)
dialog.dismiss(); continueAfterAgreement()
}
buttons.addView(rejectButton, LinearLayout.LayoutParams(0, dp(52), 1f).apply { marginEnd = dp(7) })
buttons.addView(agreeButton, LinearLayout.LayoutParams(0, dp(52), 1f).apply { marginStart = dp(7) })
val panel = LinearLayout(this).apply {
orientation = LinearLayout.VERTICAL
setPadding(dp(24), dp(25), dp(24), dp(24))
addView(title, LinearLayout.LayoutParams(-1, dp(40)))
addView(contentScroll, LinearLayout.LayoutParams(-1, dp(390)).apply { topMargin = dp(12); bottomMargin = dp(20) })
addView(buttons, LinearLayout.LayoutParams(-1, dp(52)))
background = GradientDrawable().apply { setColor(Color.WHITE); cornerRadius = dp(22).toFloat() }
}
dialog = AlertDialog.Builder(this).setView(panel).setCancelable(false).create()
dialog.show()
dialog.window?.apply {
setBackgroundDrawableResource(android.R.color.transparent)
setDimAmount(0.55f)
setGravity(Gravity.CENTER)
setLayout((resources.displayMetrics.widthPixels * 0.82f).toInt(), WindowManager.LayoutParams.WRAP_CONTENT)
}
} }
override fun initData() { override fun initData() {

View File

@@ -9,7 +9,7 @@ import androidx.viewpager.widget.PagerAdapter
import com.ck.ckcollar.app.R import com.ck.ckcollar.app.R
import com.ck.ckcollar.app.databinding.ActivityWelcomeBinding import com.ck.ckcollar.app.databinding.ActivityWelcomeBinding
import com.ck.ckcollar.app.databinding.LayoutItemWelcomeBinding import com.ck.ckcollar.app.databinding.LayoutItemWelcomeBinding
import com.ck.ckcollar.app.ui.act.login.LoginActivity import com.ck.ckcollar.app.ui.act.home.MainActivity
import com.ck.ckcollar.app.ui.base.CKBaseActivity import com.ck.ckcollar.app.ui.base.CKBaseActivity
import com.ck.ckcollar.app.utils.Const import com.ck.ckcollar.app.utils.Const
import com.cyclone.shadowsocks.utils.PreferencesUtils import com.cyclone.shadowsocks.utils.PreferencesUtils
@@ -59,11 +59,12 @@ class WelcomeActivity : CKBaseActivity() {
view.btnCome.setOnClickListener { view.btnCome.setOnClickListener {
val toPermisstionActivity = PreferencesUtils.getBolean(this@WelcomeActivity, val toPermisstionActivity = PreferencesUtils.getBolean(this@WelcomeActivity,
Const.PERMISSIONS_FIRST,false) as Boolean Const.PERMISSIONS_FIRST,false) as Boolean
if (!toPermisstionActivity){ // if (!toPermisstionActivity){
toActivity(PermisstionActivity::class.java, DataCollection()) // toActivity(PermisstionActivity::class.java, DataCollection())
}else{ // }else{
toActivity(LoginActivity::class.java, DataCollection()) // toActivity(LoginActivity::class.java, DataCollection())
} // }
toActivity(MainActivity::class.java, DataCollection())
finish() finish()
} }

View File

@@ -19,8 +19,8 @@ import pub.devrel.easypermissions.EasyPermissions
open class CKBaseActionBarActivity : TTBaseActivity(){ open class CKBaseActionBarActivity : TTBaseActivity(){
var perms_= listOf<String>(Manifest.permission.CAMERA, Manifest.permission.READ_MEDIA_IMAGES,Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE) var perms_= listOf<String>(Manifest.permission.CAMERA, Manifest.permission.READ_MEDIA_IMAGES,Manifest.permission.READ_EXTERNAL_STORAGE)
var perms_tiramisu = listOf<String>(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE) var perms_tiramisu = listOf<String>(Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE)
lateinit var rootView : View lateinit var rootView : View
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {

View File

@@ -1,23 +1,33 @@
package com.ck.ckcollar.app.ui.base package com.ck.ckcollar.app.ui.base
import android.Manifest import android.Manifest
import android.content.pm.PackageManager
import android.content.Intent
import android.graphics.drawable.ColorDrawable
import android.graphics.Color import android.graphics.Color
import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.provider.Settings
import android.util.TypedValue import android.util.TypedValue
import android.view.View import android.view.View
import android.view.Gravity
import android.view.WindowManager import android.view.WindowManager
import android.widget.ImageButton import android.widget.ImageButton
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import com.ck.ckcollar.app.CKApp import com.ck.ckcollar.app.CKApp
import com.ck.ckcollar.app.R import com.ck.ckcollar.app.R
import com.ck.ckcollar.app.ui.dialog.CKAlertDialog
import com.tt.kit.base.TTBaseActivity import com.tt.kit.base.TTBaseActivity
import com.tt.kit.utils.TTLog import com.tt.kit.utils.TTLog
import com.tt.kit.utils.TTUtils import com.tt.kit.utils.TTUtils
@@ -26,8 +36,47 @@ import pub.devrel.easypermissions.EasyPermissions
open class CKBaseActivity : TTBaseActivity(){ open class CKBaseActivity : TTBaseActivity(){
var perms_= listOf<String>(Manifest.permission.CAMERA, Manifest.permission.READ_MEDIA_IMAGES,Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE) protected open val useDarkStatusBarIcons: Boolean = true
var perms_tiramisu = listOf<String>(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE)
private var permissionDialog: AlertDialog? = null
private var pendingPermissionRequestCode: Int? = null
private var pendingPermissions: Array<String> = emptyArray()
private var settingsPermissionRequestCode: Int? = null
private var settingsPermissions: Array<String> = emptyArray()
private val permissionSettingsLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) {
val requestCode = settingsPermissionRequestCode
val permissions = settingsPermissions
settingsPermissionRequestCode = null
settingsPermissions = emptyArray()
if (requestCode != null && hasRecordPermission(permissions)) {
onPermissionsGranted(requestCode, permissions)
}
}
private val permissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { result ->
hidePermissionDialog()
val requestCode = pendingPermissionRequestCode ?: return@registerForActivityResult
val requestedPermissions = pendingPermissions
pendingPermissionRequestCode = null
pendingPermissions = emptyArray()
val denied = result.filterValues { !it }.keys.toTypedArray()
if (denied.isEmpty()) {
onPermissionsGranted(requestCode, requestedPermissions)
} else {
val permanentlyDenied = denied.any {
!ActivityCompat.shouldShowRequestPermissionRationale(this, it)
}
onPermissionsDenied(requestCode, denied, permanentlyDenied)
}
}
var perms_= listOf<String>(Manifest.permission.CAMERA, Manifest.permission.READ_MEDIA_IMAGES,Manifest.permission.READ_EXTERNAL_STORAGE)
var perms_tiramisu = listOf<String>(Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE)
var perms_carmra = listOf<String>(Manifest.permission.CAMERA) var perms_carmra = listOf<String>(Manifest.permission.CAMERA)
@@ -53,10 +102,15 @@ open class CKBaseActivity : TTBaseActivity(){
CKApp.app.activitys.add(this) CKApp.app.activitys.add(this)
setStatusBarColor(R.attr.actionBarBackground) setStatusBarColor(R.attr.actionBarBackground)
setStatusBarTextDark(useDarkStatusBarIcons)
} }
fun setStatusBarTextDark(isDark: Boolean = true) {
WindowInsetsControllerCompat(window, window.decorView).isAppearanceLightStatusBars = isDark
}
fun checkAppPermissions(){ fun checkAppPermissions(){
if (!checkPermissions()){ if (!checkPermissions()){
requstPermissions() requstPermissions()
@@ -208,10 +262,139 @@ open class CKBaseActivity : TTBaseActivity(){
} }
fun checkCameraPermissions() : Boolean{ fun checkCameraPermissions() : Boolean{
var a = 0;
return EasyPermissions.hasPermissions(this, *perms_carmra.toTypedArray()) return EasyPermissions.hasPermissions(this, *perms_carmra.toTypedArray())
} }
fun hasRecordPermission(permission: String): Boolean {
return hasRecordPermission(arrayOf(permission))
}
fun hasRecordPermission(permissions: Array<String>): Boolean {
return permissions.all {
ContextCompat.checkSelfPermission(this, it) == PackageManager.PERMISSION_GRANTED
}
}
fun getPermissionRequst(
permission: String,
requestCode: Int
) {
val isCameraPermission = permission == Manifest.permission.CAMERA
getPermissionRequst(
permission,
getString(if (isCameraPermission) R.string.camera else R.string.photo),
getString(if (isCameraPermission) R.string.camera_alert else R.string.photo_permission_alert),
requestCode
)
}
fun getPermissionRequst(
permission: String,
title: String,
content: String,
requestCode: Int
) {
getMorePermissionRequst(arrayOf(permission), title, content, requestCode)
}
fun getMorePermissionRequst(
permissions: Array<String>,
title: String,
content: String,
requestCode: Int
) {
if (hasRecordPermission(permissions)) {
onPermissionsGranted(requestCode, permissions)
return
}
CKAlertDialog(this, getString(R.string.alert), content, object : CKAlertDialog.AlertClickListener {
override fun onBack(isConfirm: Boolean) {
if (isConfirm) {
requestSystemPermissions(permissions, title, content, requestCode)
} else {
onPermissionsDenied(requestCode, permissions, false)
}
}
}).show()
}
private fun requestSystemPermissions(
permissions: Array<String>,
title: String,
content: String,
requestCode: Int
) {
pendingPermissionRequestCode = requestCode
pendingPermissions = permissions
showPermissionDialog(title, content)
permissionDialog?.window?.decorView?.post {
if (!isFinishing && pendingPermissionRequestCode == requestCode) {
permissionLauncher.launch(permissions)
}
}
}
private fun showPermissionDialog(title: String, content: String) {
hidePermissionDialog()
val view = layoutInflater.inflate(R.layout.permission_top_dialog, null)
view.findViewById<TextView>(R.id.permissionTopTitle).text = title
view.findViewById<TextView>(R.id.permissionTopContent).text = content
permissionDialog = AlertDialog.Builder(this)
.setView(view)
.create()
.also { dialog ->
dialog.setCanceledOnTouchOutside(false)
dialog.setCancelable(false)
dialog.show()
dialog.window?.apply {
setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
setGravity(Gravity.TOP)
setLayout(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT
)
}
}
}
private fun hidePermissionDialog() {
permissionDialog?.dismiss()
permissionDialog = null
}
protected open fun onPermissionsGranted(requestCode: Int, permissions: Array<String>) {
}
protected open fun onPermissionsDenied(
requestCode: Int,
permissions: Array<String>,
permanentlyDenied: Boolean
) {
if (!permanentlyDenied) return
CKAlertDialog(
this,
getString(R.string.settting_permissions),
getString(R.string.permission_settings_alert),
object : CKAlertDialog.AlertClickListener {
override fun onBack(isConfirm: Boolean) {
if (isConfirm) {
settingsPermissionRequestCode = requestCode
settingsPermissions = permissions
permissionSettingsLauncher.launch(
Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.parse("package:$packageName")
)
)
}
}
}
).show()
}
fun requstPermissions(){ fun requstPermissions(){
var perms = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { var perms = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
perms_ perms_
@@ -228,6 +411,11 @@ open class CKBaseActivity : TTBaseActivity(){
ActivityCompat.requestPermissions(this, perms.toTypedArray(), 1001) ActivityCompat.requestPermissions(this, perms.toTypedArray(), 1001)
} }
override fun onDestroy() { override fun onDestroy() {
hidePermissionDialog()
pendingPermissionRequestCode = null
pendingPermissions = emptyArray()
settingsPermissionRequestCode = null
settingsPermissions = emptyArray()
super.onDestroy() super.onDestroy()
CKApp.app.activitys.remove(this) CKApp.app.activitys.remove(this)
} }

View File

@@ -1,14 +1,21 @@
package com.ck.ckcollar.app.ui.base package com.ck.ckcollar.app.ui.base
import android.Manifest import android.Manifest
import com.ck.ckcollar.app.CKApp
import com.ck.ckcollar.app.ui.act.login.LoginActivity
import com.cyclone.shadowsocks.ui.frg.TTBaseFragment import com.cyclone.shadowsocks.ui.frg.TTBaseFragment
import com.tt.kit.model.DataCollection
import pub.devrel.easypermissions.EasyPermissions import pub.devrel.easypermissions.EasyPermissions
open class CKBaseFragment : TTBaseFragment() { open class CKBaseFragment : TTBaseFragment() {
var perms_carmra = listOf<String>(Manifest.permission.CAMERA) var perms_carmra = listOf<String>(Manifest.permission.CAMERA)
fun isUserLogin(): Boolean {
if (CKApp.app.isUserLoggedIn) return true
toActivity(LoginActivity::class.java, DataCollection())
return false
}
fun checkCameraPermissions() : Boolean{ fun checkCameraPermissions() : Boolean{

View File

@@ -28,8 +28,10 @@ import pub.devrel.easypermissions.EasyPermissions
open class CKLHBaseActionBarActivity : TTBaseActivity(){ open class CKLHBaseActionBarActivity : TTBaseActivity(){
var perms_= listOf<String>(Manifest.permission.CAMERA, Manifest.permission.READ_MEDIA_IMAGES,Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE) protected open val shouldRequestPermissionsOnCreate: Boolean = false
var perms_tiramisu = listOf<String>(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE)
var perms_= listOf<String>(Manifest.permission.CAMERA, Manifest.permission.READ_MEDIA_IMAGES,Manifest.permission.READ_EXTERNAL_STORAGE)
var perms_tiramisu = listOf<String>(Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE)
lateinit var rootView : View lateinit var rootView : View
@@ -83,7 +85,7 @@ open class CKLHBaseActionBarActivity : TTBaseActivity(){
// insets // insets
// } // }
if (!checkPermissions()){ if (shouldRequestPermissionsOnCreate && !checkPermissions()){
requstPermissions() requstPermissions()
} }

View File

@@ -28,8 +28,8 @@ import pub.devrel.easypermissions.EasyPermissions
open class CKLHBaseActivity : TTBaseActivity(){ open class CKLHBaseActivity : TTBaseActivity(){
var perms_= listOf<String>(Manifest.permission.CAMERA, Manifest.permission.READ_MEDIA_IMAGES,Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE) var perms_= listOf<String>(Manifest.permission.CAMERA, Manifest.permission.READ_MEDIA_IMAGES,Manifest.permission.READ_EXTERNAL_STORAGE)
var perms_tiramisu = listOf<String>(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE) var perms_tiramisu = listOf<String>(Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
// AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) // AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
@@ -74,9 +74,9 @@ open class CKLHBaseActivity : TTBaseActivity(){
// getWindow().setStatusBarColor(Color.TRANSPARENT); // getWindow().setStatusBarColor(Color.TRANSPARENT);
if (!checkPermissions()){ // if (!checkPermissions()){
requstPermissions() // requstPermissions()
} // }
} }

View File

@@ -1,6 +1,7 @@
package com.ck.ckcollar.app.ui.dialog package com.ck.ckcollar.app.ui.dialog
import android.content.Context import android.content.Context
import android.content.res.ColorStateList
import android.text.TextUtils import android.text.TextUtils
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@@ -33,8 +34,15 @@ class CKEditPhoneDialog(
dialogAlertBinding.title.text = title dialogAlertBinding.title.text = title
} }
dialogAlertBinding.btnSendCode.setOnClickListener { sendCode() } dialogAlertBinding.btnSendCode.setOnClickListener { sendCode() }
dialogAlertBinding.btnSendCode.setTextColor(
ColorStateList(
arrayOf(intArrayOf(-android.R.attr.state_enabled), intArrayOf()),
intArrayOf(mContext.getColor(R.color.textSecondColor), mContext.getColor(R.color.appStyle))
)
)
dialogAlertBinding.cancelButton.setOnClickListener(object : View.OnClickListener { dialogAlertBinding.cancelButton.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View?) { override fun onClick(v: View?) {
dialogAlertBinding.btnSendCode.stopCountDown()
cancel() cancel()
} }
}) })
@@ -72,7 +80,7 @@ class CKEditPhoneDialog(
add(TTRequestData("smsCode",dialogAlertBinding.textCode.text.toString())) add(TTRequestData("smsCode",dialogAlertBinding.textCode.text.toString()))
},object : ICallback{ },object : ICallback{
override fun onSuccess(data: String) { override fun onSuccess(data: String) {
mContext.toast(mContext.getString(R.string.send_success)) mContext.toast(mContext.getString(R.string.edit_success))
cancel() cancel()
} }
@@ -94,7 +102,8 @@ class CKEditPhoneDialog(
add(TTRequestData("scene","changePhone")) add(TTRequestData("scene","changePhone"))
},object : ICallback{ },object : ICallback{
override fun onSuccess(data: String) { override fun onSuccess(data: String) {
mContext.toast(mContext.getString(R.string.edit_success)) mContext.toast(mContext.getString(R.string.verification_code_sent))
dialogAlertBinding.btnSendCode.startCountDown()
alertClickListener.onBack(dialogAlertBinding.textPhone.text.toString()) alertClickListener.onBack(dialogAlertBinding.textPhone.text.toString())
} }

View File

@@ -35,6 +35,10 @@ class CKPhotoDialog(
} }
}) })
dialogMakePhotoBinding.cancelButton.setOnClickListener {
cancel()
}
setContentView(dialogMakePhotoBinding.root,ViewGroup.LayoutParams(TTUtils.width, ViewGroup.LayoutParams.WRAP_CONTENT)) setContentView(dialogMakePhotoBinding.root,ViewGroup.LayoutParams(TTUtils.width, ViewGroup.LayoutParams.WRAP_CONTENT))
} catch (e: Exception) { } catch (e: Exception) {

View File

@@ -19,10 +19,13 @@ class CKUpdateAlertDialog(
var alertClickListener: AlertClickListener var alertClickListener: AlertClickListener
) : TTBaseDialog(mContext){ ) : TTBaseDialog(mContext){
private var binding: DialogUpdateAlertBinding? = null
override fun show() { override fun show() {
try { try {
var dialogAlertBinding = val dialogAlertBinding =
DialogUpdateAlertBinding.inflate(LayoutInflater.from(mContext)) DialogUpdateAlertBinding.inflate(LayoutInflater.from(mContext))
binding = dialogAlertBinding
dialogAlertBinding.textAlert.text = alertText dialogAlertBinding.textAlert.text = alertText
if (isForce){ if (isForce){
@@ -39,8 +42,6 @@ class CKUpdateAlertDialog(
//dialogView.findViewById(R.id.photo).setVisibility(View.GONE); //dialogView.findViewById(R.id.photo).setVisibility(View.GONE);
dialogAlertBinding.btnConfirm.setOnClickListener(object : View.OnClickListener { dialogAlertBinding.btnConfirm.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View?) { override fun onClick(v: View?) {
// TODO Auto-generated method stub
cancel()
alertClickListener.onBack(true) alertClickListener.onBack(true)
} }
}) })
@@ -55,6 +56,34 @@ class CKUpdateAlertDialog(
setCancelable(false) setCancelable(false)
} }
fun showDownloadProgress() {
binding?.apply {
progressContainer.visibility = View.VISIBLE
btnConfirm.visibility = View.GONE
btnCenlel.visibility = View.GONE
textAlert.visibility = View.GONE
title.text = mContext.getString(com.ck.ckcollar.app.R.string.update_downloading, 0)
}
}
fun updateProgress(progress: Int) {
binding?.apply {
updateProgress.progress = progress
progressText.text = "$progress%"
title.text = mContext.getString(com.ck.ckcollar.app.R.string.update_downloading, progress)
}
}
fun showDownloadError() {
binding?.apply {
progressContainer.visibility = View.GONE
btnConfirm.visibility = View.VISIBLE
btnCenlel.visibility = if (isForce) View.GONE else View.VISIBLE
textAlert.visibility = View.VISIBLE
title.text = mContext.getString(com.ck.ckcollar.app.R.string.update_content)
}
}
interface AlertClickListener { interface AlertClickListener {
fun onBack(isConfirm : Boolean) fun onBack(isConfirm : Boolean)

View File

@@ -12,6 +12,9 @@ object Const {
const val LOGIN_NAME = "login_name" const val LOGIN_NAME = "login_name"
const val LOGIN_PWD = "login_pwd" const val LOGIN_PWD = "login_pwd"
const val TOKEN = "token" const val TOKEN = "token"
const val MEMBER_PRICE = "member_price"
const val MEMBER_PRICE_CACHE_TIME = "member_price_cache_time"
//微信app-id
const val WX_APP_ID = "wx7681e74df7d88ddc" const val WX_APP_ID = "wx7681e74df7d88ddc"
} }

View File

@@ -0,0 +1,81 @@
package com.ck.ckcollar.app.utils
import java.time.DateTimeException
import java.time.LocalDate
import java.time.format.DateTimeFormatter
import java.time.format.ResolverStyle
/** 校验中国大陆地区的 15 位和 18 位居民身份证号码。 */
object IDCardValidate {
private val weights = intArrayOf(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2)
private val verifyCodes = charArrayOf('1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2')
private val areaCodes = setOf(
"11", "12", "13", "14", "15",
"21", "22", "23",
"31", "32", "33", "34", "35", "36", "37",
"41", "42", "43", "44", "45", "46",
"50", "51", "52", "53", "54",
"61", "62", "63", "64", "65",
"71", "81", "82", "91"
)
private val birthDateFormatter = DateTimeFormatter
.ofPattern("uuuuMMdd")
.withResolverStyle(ResolverStyle.STRICT)
private val earliestBirthDate = LocalDate.of(1900, 1, 1)
@JvmStatic
fun validate_effective(idcardNumber: String?): Boolean = validateEffective(idcardNumber)
/**
* 为兼容 Water 项目而保留,第二个参数不会影响校验结果。
*/
@JvmStatic
@Suppress("UNUSED_PARAMETER")
fun validate_effective(idcardNumber: String?, isreturn_AutoCard: Boolean): Boolean =
validateEffective(idcardNumber)
@JvmStatic
fun validateEffective(idCardNumber: String?): Boolean {
val source = idCardNumber?.trim()?.uppercase() ?: return false
val cardNumber = when (source.length) {
OLD_CARD_NUMBER_LENGTH -> convertToNewCardNumber(source) ?: return false
NEW_CARD_NUMBER_LENGTH -> source
else -> return false
}
if (!cardNumber.take(17).all(Char::isDigit)) return false
if (cardNumber.last() != 'X' && !cardNumber.last().isDigit()) return false
if (cardNumber.substring(0, 2) !in areaCodes) return false
if (!hasValidBirthDate(cardNumber.substring(6, 14))) return false
return cardNumber.last() == calculateVerifyCode(cardNumber)
}
private fun convertToNewCardNumber(oldCardNumber: String): String? {
if (!oldCardNumber.all(Char::isDigit)) return null
val firstSeventeen = buildString(17) {
append(oldCardNumber, 0, 6)
append("19")
append(oldCardNumber, 6, oldCardNumber.length)
}
return firstSeventeen + calculateVerifyCode(firstSeventeen)
}
private fun hasValidBirthDate(value: String): Boolean {
val birthDate = try {
LocalDate.parse(value, birthDateFormatter)
} catch (_: DateTimeException) {
return false
}
return birthDate.isAfter(earliestBirthDate) && birthDate.isBefore(LocalDate.now())
}
private fun calculateVerifyCode(cardNumber: CharSequence): Char {
val sum = weights.indices.sumOf { index ->
(cardNumber[index] - '0') * weights[index]
}
return verifyCodes[sum % 11]
}
private const val NEW_CARD_NUMBER_LENGTH = 18
private const val OLD_CARD_NUMBER_LENGTH = 15
}

View File

@@ -0,0 +1,53 @@
package com.ck.ckcollar.app.utils
import android.content.Context
import java.io.File
import java.util.Locale
import top.zibin.luban.Luban
import top.zibin.luban.OnCompressListener
object LubanCompressUtil {
private const val DEFAULT_IGNORE_SIZE_KB = 100
interface CompressCallback {
fun success(file: File)
fun fail(failMsg: String)
}
fun getInstance(): LubanCompressUtil {
return this
}
fun getCompressFile(
context: Context,
oldFile: File,
callback: CompressCallback?
) {
if (!oldFile.exists() || !oldFile.isFile) {
callback?.fail("图片文件不存在")
return
}
Luban.with(context.applicationContext)
.load(oldFile)
.ignoreBy(DEFAULT_IGNORE_SIZE_KB)
.filter { path ->
path.isNotBlank() && !path.lowercase(Locale.ROOT).endsWith(".gif")
}
.setCompressListener(object : OnCompressListener {
override fun onStart() {
}
override fun onSuccess(file: File) {
callback?.success(file)
}
override fun onError(error: Throwable) {
callback?.fail(error.message ?: "图片压缩失败")
}
})
.launch()
}
}

View File

@@ -0,0 +1,31 @@
package com.ck.ckcollar.app.utils
import android.content.Context
import com.cyclone.shadowsocks.utils.PreferencesUtils
object MemberPriceCache {
private const val CACHE_VALID_DURATION = 24 * 60 * 60 * 1000L
fun getPrice(context: Context): Double? {
return PreferencesUtils.getString(context, Const.MEMBER_PRICE, "")
.toString()
.toDoubleOrNull()
}
fun isExpired(context: Context): Boolean {
val cacheTime = PreferencesUtils.getString(context, Const.MEMBER_PRICE_CACHE_TIME, "0")
.toString()
.toLongOrNull() ?: 0L
return System.currentTimeMillis() - cacheTime >= CACHE_VALID_DURATION
}
fun save(context: Context, price: Double) {
PreferencesUtils.putString(context, Const.MEMBER_PRICE, price.toString())
PreferencesUtils.putString(
context,
Const.MEMBER_PRICE_CACHE_TIME,
System.currentTimeMillis().toString()
)
}
}

View File

@@ -2,4 +2,8 @@ package com.ck.ckcollar.app.utils.networkone
interface ICallback { interface ICallback {
fun onSuccess(data: String) fun onSuccess(data: String)
fun onFailed(code: String, msg: String) fun onFailed(code: String, msg: String)
fun onFailed(code: String, msg: String, data: String) {
onFailed(code, msg)
}
fun onComplete() {}
} }

View File

@@ -78,7 +78,9 @@ object TTHttpClient {
val string = response.body?.string() val string = response.body?.string()
string?.let { TTLog.e("response", actionCode + "====" + it) } string?.let { TTLog.e("response", actionCode + "====" + it) }
var model = JSONObject(string) var model = JSONObject(string)
if (isSusscee(model)) { // A withdrawal code of 201 means the transfer bill was created
// and the client must continue with WeChat confirmation.
if (isSusscee(model) || (actionCode == "提现" && getCode(model) == "201")) {
activity.runOnUiThread { activity.runOnUiThread {
activity.hiddenProgeassDialog() activity.hiddenProgeassDialog()
iCallback.onSuccess(getData(model)) iCallback.onSuccess(getData(model))
@@ -137,7 +139,10 @@ object TTHttpClient {
val string = response.body?.string() val string = response.body?.string()
string?.let { TTLog.e("response", actionCode + "====" + it) } string?.let { TTLog.e("response", actionCode + "====" + it) }
var model = JSONObject(string) var model = JSONObject(string)
if (isSusscee(model)) { // code 201 means the withdrawal bill was created and the
// client must continue with WeChat confirmation. Keep the
// response data available to the withdrawal screen.
if (isSusscee(model) || (actionCode == "提现" && getCode(model) == "201")) {
activity.runOnUiThread { activity.runOnUiThread {
activity.hiddenProgeassDialog() activity.hiddenProgeassDialog()
iCallback.onSuccess(getData(model)) iCallback.onSuccess(getData(model))
@@ -429,10 +434,12 @@ object TTHttpClient {
} }
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
iCallback.onFailed("500", "网络连接失败,请检查网络") iCallback.onComplete()
} }
}catch (e: Exception){ }catch (e: Exception){
withContext(Dispatchers.Main) {
iCallback.onFailed("500", e.message.orEmpty())
}
} }
} }
@@ -484,7 +491,7 @@ fun postJson(
} else { } else {
activity.runOnUiThread { activity.runOnUiThread {
activity.hiddenProgeassDialog() activity.hiddenProgeassDialog()
iCallback.onFailed(getCode(model), getMessage(model)) iCallback.onFailed(getCode(model), getMessage(model), model.toString())
} }
} }
} }

View File

@@ -2,6 +2,7 @@ package com.ck.ckcollar.app.utils.networkone.interceptor
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import com.ck.ckcollar.app.CKApp
import com.ck.ckcollar.app.ui.act.login.LoginActivity import com.ck.ckcollar.app.ui.act.login.LoginActivity
import com.google.gson.Gson import com.google.gson.Gson
import com.tt.kit.networktwo.model.TTResposeData import com.tt.kit.networktwo.model.TTResposeData
@@ -22,6 +23,7 @@ class ResponseInterceptor(val context : Context) : Interceptor{
TTLog.i("ResponseInterceptor", "intercept model:" + body) TTLog.i("ResponseInterceptor", "intercept model:" + body)
// token失效统一处理 // token失效统一处理
if (model.code == 401){ if (model.code == 401){
CKApp.app.clearLoginState()
var intent = Intent(context, LoginActivity::class.java) var intent = Intent(context, LoginActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
context.startActivity(intent) context.startActivity(intent)

View File

@@ -3,24 +3,63 @@ package com.ck.ckcollar.app.widget
import android.content.Context import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import android.view.MotionEvent import android.view.MotionEvent
import androidx.appcompat.widget.AppCompatImageView
import androidx.viewpager.widget.ViewPager import androidx.viewpager.widget.ViewPager
class CKViewPager : ViewPager{ class CKViewPager : ViewPager{
private var isMultiTouchGesture = false
constructor(context: Context) : super(context) constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
when (ev.actionMasked) {
MotionEvent.ACTION_DOWN -> isMultiTouchGesture = false
MotionEvent.ACTION_POINTER_DOWN -> {
if (ev.pointerCount > 1) {
isMultiTouchGesture = true
}
}
}
return try {
super.dispatchTouchEvent(ev)
} finally {
// dispatchTouchEvent always sees the terminal event, even when
// PhotoView has disabled parent interception during scaling.
if (ev.actionMasked == MotionEvent.ACTION_UP ||
ev.actionMasked == MotionEvent.ACTION_CANCEL
) {
isMultiTouchGesture = false
}
}
}
override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean { override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
if (ev == null) return false
// Keep the complete pinch sequence in PhotoView. If ViewPager intercepts
// one MOVE event, the child receives CANCEL and scaling stops entirely.
if (isMultiTouchGesture || ev.pointerCount > 1) {
return false
}
try { try {
return super.onInterceptTouchEvent(ev) return super.onInterceptTouchEvent(ev)
} catch (e: IllegalArgumentException) {
}catch (e : Exception){
e.printStackTrace() e.printStackTrace()
} }
return false return false
} }
override fun onTouchEvent(ev: MotionEvent?): Boolean {
if (ev == null) return false
return try {
super.onTouchEvent(ev)
} catch (e: IllegalArgumentException) {
e.printStackTrace()
false
}
}
} }

View File

@@ -4,6 +4,7 @@ import android.app.Activity
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import com.ck.ckcollar.app.CKApp import com.ck.ckcollar.app.CKApp
import com.ck.ckcollar.app.ui.act.balance.WithDrawActivity
import com.ck.ckcollar.app.ui.act.login.LoginActivity import com.ck.ckcollar.app.ui.act.login.LoginActivity
import com.ck.ckcollar.app.ui.act.user.UserInfoActivity import com.ck.ckcollar.app.ui.act.user.UserInfoActivity
import com.ck.ckcollar.app.utils.Const import com.ck.ckcollar.app.utils.Const
@@ -15,6 +16,7 @@ import com.tencent.mm.opensdk.openapi.IWXAPI
import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler
import com.tencent.mm.opensdk.openapi.WXAPIFactory import com.tencent.mm.opensdk.openapi.WXAPIFactory
import com.tt.kit.utils.TTLog import com.tt.kit.utils.TTLog
import com.tt.kit.utils.LiveDataBus
class WXEntryActivity : Activity(), IWXAPIEventHandler { class WXEntryActivity : Activity(), IWXAPIEventHandler {
@@ -43,6 +45,13 @@ class WXEntryActivity : Activity(), IWXAPIEventHandler {
} }
override fun onResp(resp: BaseResp?) { override fun onResp(resp: BaseResp?) {
if (resp?.type == ConstantsAPI.COMMAND_OPEN_BUSINESS_VIEW) {
LiveDataBus.get()
.with(WithDrawActivity.WX_WITHDRAW_RESULT)
.value = resp.errCode
finish()
return
}
if (resp!!.getType() === ConstantsAPI.COMMAND_SENDAUTH) { if (resp!!.getType() === ConstantsAPI.COMMAND_SENDAUTH) {
val authResp = resp as SendAuth.Resp val authResp = resp as SendAuth.Resp
val code = authResp.code val code = authResp.code

View File

@@ -0,0 +1,51 @@
package com.ck.ckcollar.app.wxapi
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.widget.Toast
import com.ck.ckcollar.app.ui.act.balance.RechargeActivity
import com.ck.ckcollar.app.utils.Const
import com.tencent.mm.opensdk.modelbase.BaseReq
import com.tencent.mm.opensdk.modelbase.BaseResp
import com.tencent.mm.opensdk.constants.ConstantsAPI
import com.ck.ckcollar.app.ui.act.balance.WithDrawActivity
import com.tencent.mm.opensdk.openapi.IWXAPI
import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler
import com.tencent.mm.opensdk.openapi.WXAPIFactory
import com.tt.kit.utils.LiveDataBus
class WXPayEntryActivity : Activity(), IWXAPIEventHandler {
private lateinit var api: IWXAPI
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
api = WXAPIFactory.createWXAPI(this, Const.WX_APP_ID, false)
api.handleIntent(intent, this)
}
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
setIntent(intent)
api.handleIntent(intent, this)
}
override fun onReq(req: BaseReq?) = Unit
override fun onResp(resp: BaseResp?) {
val resultCode = resp?.errCode ?: -1
if (resp?.type == ConstantsAPI.COMMAND_OPEN_BUSINESS_VIEW) {
LiveDataBus.get().with(WithDrawActivity.WX_WITHDRAW_RESULT).value = resultCode
finish()
return
}
val message = when (resultCode) {
BaseResp.ErrCode.ERR_OK -> "微信支付成功"
BaseResp.ErrCode.ERR_USER_CANCEL -> "已取消微信支付"
else -> "微信支付失败"
}
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
LiveDataBus.get().with(RechargeActivity.WX_PAY_RESULT).value = resultCode
finish()
}
}

View File

@@ -88,6 +88,7 @@
android:textColorHint="@color/textSecondColor" android:textColorHint="@color/textSecondColor"
android:maxLength="11" android:maxLength="11"
android:maxLines="1" android:maxLines="1"
android:singleLine="true"
android:inputType="number" android:inputType="number"
android:textSize="14sp"></com.ck.ckcollar.app.widget.CKEditView> android:textSize="14sp"></com.ck.ckcollar.app.widget.CKEditView>
@@ -165,7 +166,8 @@
android:textColorHint="@color/textSecondColor" android:textColorHint="@color/textSecondColor"
android:maxLength="50" android:maxLength="50"
android:maxLines="3" android:maxLines="3"
android:textSize="14sp"></com.ck.ckcollar.app.widget.CKEditView> android:textSize="14sp"
android:singleLine="true"></com.ck.ckcollar.app.widget.CKEditView>
</com.ck.ckcollar.app.widget.CKLinearLayout> </com.ck.ckcollar.app.widget.CKLinearLayout>

View File

@@ -102,7 +102,7 @@
android:text="@string/no_reason_text" android:text="@string/no_reason_text"
android:background="@drawable/bg_cz_button" android:background="@drawable/bg_cz_button"
android:paddingHorizontal="5dp" android:paddingHorizontal="5dp"
></com.ck.ckcollar.app.widget.CKTextView> android:visibility="gone"/>
</com.ck.ckcollar.app.widget.CKLinearLayout> </com.ck.ckcollar.app.widget.CKLinearLayout>
<com.ck.ckcollar.app.widget.CKLinearLayout <com.ck.ckcollar.app.widget.CKLinearLayout

View File

@@ -35,8 +35,8 @@
<com.ck.ckcollar.app.widget.CKTextView <com.ck.ckcollar.app.widget.CKTextView
android:id="@+id/textBalance" android:id="@+id/textBalance"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="50dp"
android:text="0.00" android:gravity="center_vertical"
android:textColor="@color/textColor" android:textColor="@color/textColor"
android:textSize="38sp" android:textSize="38sp"
android:textStyle="bold" android:textStyle="bold"

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<com.ck.ckcollar.app.widget.CKLinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <com.ck.ckcollar.app.widget.CKLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:orientation="vertical"
@@ -20,7 +21,6 @@
android:orientation="horizontal" android:orientation="horizontal"
android:background="@color/white" android:background="@color/white"
android:gravity="center_vertical" android:gravity="center_vertical"
android:paddingHorizontal="20dp"
> >
<com.ck.ckcollar.app.widget.CKImageView <com.ck.ckcollar.app.widget.CKImageView
android:id="@+id/btnKeyboard" android:id="@+id/btnKeyboard"
@@ -30,39 +30,89 @@
android:visibility="gone" android:visibility="gone"
></com.ck.ckcollar.app.widget.CKImageView> ></com.ck.ckcollar.app.widget.CKImageView>
<com.ck.ckcollar.app.widget.CKEditView <LinearLayout
android:id="@+id/editMessage" android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<FrameLayout
android:id="@+id/contentImagePreview"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginStart="12dp"
android:layout_marginTop="8dp"
android:visibility="gone">
<com.ck.ckcollar.app.widget.CKRoundImageView
android:id="@+id/imagePreview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
app:roundRadius="6dp" />
<ImageView
android:id="@+id/btnDeleteImage"
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_gravity="end|top"
android:layout_margin="4dp"
android:contentDescription="@null"
android:src="@mipmap/icon_img_del_red" />
</FrameLayout>
<LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:minHeight="34dp" android:orientation="horizontal"
android:gravity="center_vertical">
<com.ck.ckcollar.app.widget.CKEditView
android:id="@+id/editMessage"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:minHeight="34dp"
android:textColor="@color/textColor" android:textColor="@color/textColor"
android:textSize="14sp" android:textSize="14sp"
android:textColorHint="@color/textColor" android:textColorHint="@color/textColor"
android:hint="@string/please_input_message" android:hint="@string/please_input_message"
android:paddingHorizontal="16dp" android:paddingHorizontal="16dp"
android:paddingVertical="5dp" android:paddingVertical="8dp"
android:layout_marginVertical="10dp" android:layout_marginVertical="10dp"
android:layout_marginHorizontal="12dp" android:layout_marginHorizontal="12dp"
android:background="@drawable/bg_input_message" android:background="@drawable/bg_input_message"
android:imeOptions="actionSend" android:imeOptions="actionSend"
android:inputType="text" android:inputType="text"
android:maxLength="100" android:maxHeight="70dp"
></com.ck.ckcollar.app.widget.CKEditView> android:maxLines="4"
android:scrollbars="vertical"
android:maxLength="100" />
<com.ck.ckcollar.app.widget.CKImageView <com.ck.ckcollar.app.widget.CKImageView
android:id="@+id/btnSmile" android:id="@+id/btnSmile"
android:layout_width="wrap_content" android:layout_width="24dp"
android:layout_height="wrap_content" android:layout_height="24dp"
android:src="@mipmap/image_smile" android:src="@mipmap/image_smile"
></com.ck.ckcollar.app.widget.CKImageView> android:visibility="gone"/>
<com.ck.ckcollar.app.widget.CKImageView <com.ck.ckcollar.app.widget.CKImageView
android:id="@+id/btnMore" android:id="@+id/btnMore"
android:layout_width="wrap_content" android:layout_width="24dp"
android:layout_height="wrap_content" android:layout_height="24dp"
android:src="@mipmap/image_more" android:src="@mipmap/image_more"
android:layout_marginLeft="12dp" android:layout_marginLeft="12dp"
></com.ck.ckcollar.app.widget.CKImageView> android:layout_marginRight="15dp"/>
<com.ck.ckcollar.app.widget.CKImageView
android:id="@+id/btnSend"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@mipmap/icon_send_yellow"
android:layout_marginLeft="12dp"
android:layout_marginRight="15dp"
android:visibility="gone"/>
</LinearLayout>
</LinearLayout>
</com.ck.ckcollar.app.widget.CKLinearLayout> </com.ck.ckcollar.app.widget.CKLinearLayout>
<com.ck.ckcollar.app.widget.CKLinearLayout <com.ck.ckcollar.app.widget.CKLinearLayout

View File

@@ -165,6 +165,16 @@
android:background="@drawable/bg_login_button" android:background="@drawable/bg_login_button"
></com.ck.ckcollar.app.widget.CKButton> ></com.ck.ckcollar.app.widget.CKButton>
<com.ck.ckcollar.app.widget.CKButton
android:id="@+id/btnQuickLogin"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginTop="10dp"
android:background="@drawable/bg_login_button"
android:text="临时快捷登录"
android:textColor="@color/buttonTextColor"
android:visibility="gone"/>
<com.ck.ckcollar.app.widget.CKLinearLayout <com.ck.ckcollar.app.widget.CKLinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="30dp" android:layout_height="30dp"

View File

@@ -36,7 +36,7 @@
<com.ck.ckcollar.app.widget.CKLinearLayout <com.ck.ckcollar.app.widget.CKLinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="52dp" android:layout_height="60dp"
android:background="?attr/mainBackground" android:background="?attr/mainBackground"
android:orientation="horizontal" android:orientation="horizontal"
> >

View File

@@ -33,16 +33,21 @@
android:orientation="vertical" android:orientation="vertical"
> >
<com.ck.ckcollar.app.widget.CKLinearLayout <com.ck.ckcollar.app.widget.CKLinearLayout
android:id="@+id/priceContent"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="58dp"
android:orientation="horizontal"> android:baselineAligned="true"
android:baselineAlignedChildIndex="1"
android:gravity="bottom"
android:orientation="horizontal"
android:visibility="invisible">
<com.ck.ckcollar.app.widget.CKTextView <com.ck.ckcollar.app.widget.CKTextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="¥" android:text="¥"
android:textColor="@color/color_7B4B12" android:textColor="@color/color_7B4B12"
android:textSize="22sp"></com.ck.ckcollar.app.widget.CKTextView> android:textSize="22sp"/>
<com.ck.ckcollar.app.widget.CKTextView <com.ck.ckcollar.app.widget.CKTextView
android:id="@+id/textMoney" android:id="@+id/textMoney"
@@ -51,14 +56,15 @@
android:text="" android:text=""
android:textColor="@color/color_7B4B12" android:textColor="@color/color_7B4B12"
android:textSize="48sp" android:textSize="48sp"
android:textStyle="bold"></com.ck.ckcollar.app.widget.CKTextView> android:textStyle="bold"/>
<com.ck.ckcollar.app.widget.CKTextView <com.ck.ckcollar.app.widget.CKTextView
android:id="@+id/tv_month"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="/月" android:text="/月"
android:textColor="@color/color_7B4B12" android:textColor="@color/color_7B4B12"
android:textSize="22sp"></com.ck.ckcollar.app.widget.CKTextView> android:textSize="22sp"/>
</com.ck.ckcollar.app.widget.CKLinearLayout> </com.ck.ckcollar.app.widget.CKLinearLayout>
@@ -71,7 +77,7 @@
android:gravity="center" android:gravity="center"
android:text="@string/pet_member_open_now" android:text="@string/pet_member_open_now"
android:textColor="@color/color_CACACA" android:textColor="@color/color_CACACA"
android:textSize="16sp"></com.ck.ckcollar.app.widget.CKTextView> android:textSize="16sp"/>
</com.ck.ckcollar.app.widget.CKLinearLayout> </com.ck.ckcollar.app.widget.CKLinearLayout>
<com.ck.ckcollar.app.widget.CKLinearLayout <com.ck.ckcollar.app.widget.CKLinearLayout
@@ -93,7 +99,7 @@
android:textColor="@color/color_7B4B12" android:textColor="@color/color_7B4B12"
android:textSize="22sp" android:textSize="22sp"
android:textStyle="bold" android:textStyle="bold"
></com.ck.ckcollar.app.widget.CKTextView> />
<com.ck.ckcollar.app.widget.CKTextView <com.ck.ckcollar.app.widget.CKTextView
android:id="@+id/textMemberDate" android:id="@+id/textMemberDate"
@@ -101,7 +107,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/deadline_date" android:text="@string/deadline_date"
android:textColor="@color/color_7B4B12" android:textColor="@color/color_7B4B12"
android:textSize="16sp"></com.ck.ckcollar.app.widget.CKTextView> android:textSize="16sp"/>
</com.ck.ckcollar.app.widget.CKLinearLayout> </com.ck.ckcollar.app.widget.CKLinearLayout>
@@ -260,9 +266,9 @@
android:id="@+id/textNode" android:id="@+id/textNode"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textSize="16sp" android:textSize="14sp"
android:textColor="@color/color_CACACA" android:textColor="@color/color_CACACA"
android:text="" android:text="商城商品享受折扣,开通会员赠送积分"
android:layout_marginTop="20dp" android:layout_marginTop="20dp"
></com.ck.ckcollar.app.widget.CKTextView> ></com.ck.ckcollar.app.widget.CKTextView>

View File

@@ -80,18 +80,34 @@
android:layout_height="match_parent"> android:layout_height="match_parent">
<com.scwang.smartrefresh.layout.header.ClassicsHeader <com.scwang.smartrefresh.layout.header.ClassicsHeader
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"></com.scwang.smartrefresh.layout.header.ClassicsHeader> android:layout_height="wrap_content"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView" android:id="@+id/recyclerView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:paddingHorizontal="20dp" android:paddingHorizontal="20dp"
android:layout_marginVertical="12dp" android:layout_marginVertical="12dp" />
></androidx.recyclerview.widget.RecyclerView>
<RelativeLayout
android:id="@+id/rel_noresult"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<include
android:id="@+id/include_noresult"
layout="@layout/include_no_result_layout" />
</RelativeLayout>
</FrameLayout>
<com.scwang.smartrefresh.layout.footer.ClassicsFooter <com.scwang.smartrefresh.layout.footer.ClassicsFooter
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"></com.scwang.smartrefresh.layout.footer.ClassicsFooter> android:layout_height="wrap_content"/>
</com.scwang.smartrefresh.layout.SmartRefreshLayout> </com.scwang.smartrefresh.layout.SmartRefreshLayout>
</com.ck.ckcollar.app.widget.CKLinearLayout> </com.ck.ckcollar.app.widget.CKLinearLayout>

View File

@@ -49,38 +49,6 @@
android:layout_marginBottom="10dp" android:layout_marginBottom="10dp"
></com.ck.ckcollar.app.widget.CKTextView> ></com.ck.ckcollar.app.widget.CKTextView>
<com.ck.ckcollar.app.widget.CKLinearLayout
android:id="@+id/btnAli"
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal"
android:paddingHorizontal="20dp"
android:background="@drawable/bg_view_gray_radius_12_stroke_1"
android:gravity="center_vertical"
>
<com.ck.ckcollar.app.widget.CKImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/image_ali"
></com.ck.ckcollar.app.widget.CKImageView>
<com.ck.ckcollar.app.widget.CKTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="14sp"
android:textColor="@color/textColor"
android:text="@string/alipay"
android:paddingLeft="8dp"
></com.ck.ckcollar.app.widget.CKTextView>
<com.ck.ckcollar.app.widget.CKImageView
android:id="@+id/image1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/image_address_check_select"
></com.ck.ckcollar.app.widget.CKImageView>
</com.ck.ckcollar.app.widget.CKLinearLayout>
<com.ck.ckcollar.app.widget.CKLinearLayout <com.ck.ckcollar.app.widget.CKLinearLayout
android:id="@+id/btnWX" android:id="@+id/btnWX"
@@ -91,7 +59,7 @@
android:background="@drawable/bg_view_gray_radius_12_stroke_1" android:background="@drawable/bg_view_gray_radius_12_stroke_1"
android:gravity="center_vertical" android:gravity="center_vertical"
android:layout_marginTop="10dp" android:layout_marginTop="10dp"
android:visibility="gone" android:visibility="visible"
> >
<com.ck.ckcollar.app.widget.CKImageView <com.ck.ckcollar.app.widget.CKImageView
@@ -113,10 +81,46 @@
android:id="@+id/image2" android:id="@+id/image2"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:src="@mipmap/image_address_check_select"
></com.ck.ckcollar.app.widget.CKImageView>
</com.ck.ckcollar.app.widget.CKLinearLayout>
<com.ck.ckcollar.app.widget.CKLinearLayout
android:id="@+id/btnAli"
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal"
android:paddingHorizontal="20dp"
android:background="@drawable/bg_view_gray_radius_12_stroke_1"
android:gravity="center_vertical"
android:layout_marginTop="10dp">
<com.ck.ckcollar.app.widget.CKImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/image_ali"
></com.ck.ckcollar.app.widget.CKImageView>
<com.ck.ckcollar.app.widget.CKTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="14sp"
android:textColor="@color/textColor"
android:text="@string/alipay"
android:paddingLeft="8dp"
></com.ck.ckcollar.app.widget.CKTextView>
<com.ck.ckcollar.app.widget.CKImageView
android:id="@+id/image1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/image_address_check_narmal" android:src="@mipmap/image_address_check_narmal"
></com.ck.ckcollar.app.widget.CKImageView> ></com.ck.ckcollar.app.widget.CKImageView>
</com.ck.ckcollar.app.widget.CKLinearLayout> </com.ck.ckcollar.app.widget.CKLinearLayout>
<com.ck.ckcollar.app.widget.CKLinearLayout <com.ck.ckcollar.app.widget.CKLinearLayout
android:id="@+id/btnBalance" android:id="@+id/btnBalance"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@@ -263,7 +263,7 @@
android:orientation="horizontal" android:orientation="horizontal"
android:gravity="center_vertical" android:gravity="center_vertical"
android:layout_marginTop="10dp" android:layout_marginTop="10dp"
android:visibility="gone" android:visibility="visible"
> >
<com.ck.ckcollar.app.widget.CKImageView <com.ck.ckcollar.app.widget.CKImageView
@@ -295,7 +295,6 @@
android:layout_height="50dp" android:layout_height="50dp"
android:orientation="horizontal" android:orientation="horizontal"
android:gravity="center_vertical" android:gravity="center_vertical"
android:layout_marginTop="10dp"
> >
<com.ck.ckcollar.app.widget.CKImageView <com.ck.ckcollar.app.widget.CKImageView
@@ -317,7 +316,7 @@
android:id="@+id/image1" android:id="@+id/image1"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:src="@mipmap/image_address_check_select" android:src="@mipmap/image_address_check_narmal"
></com.ck.ckcollar.app.widget.CKImageView> ></com.ck.ckcollar.app.widget.CKImageView>
</com.ck.ckcollar.app.widget.CKLinearLayout> </com.ck.ckcollar.app.widget.CKLinearLayout>

View File

@@ -232,7 +232,7 @@
android:orientation="horizontal" android:orientation="horizontal"
android:gravity="center_vertical" android:gravity="center_vertical"
android:layout_marginTop="10dp" android:layout_marginTop="10dp"
android:visibility="gone" android:visibility="visible"
> >
<com.ck.ckcollar.app.widget.CKImageView <com.ck.ckcollar.app.widget.CKImageView
@@ -264,7 +264,6 @@
android:layout_height="50dp" android:layout_height="50dp"
android:orientation="horizontal" android:orientation="horizontal"
android:gravity="center_vertical" android:gravity="center_vertical"
android:layout_marginTop="10dp"
> >
<com.ck.ckcollar.app.widget.CKImageView <com.ck.ckcollar.app.widget.CKImageView
@@ -286,7 +285,7 @@
android:id="@+id/image1" android:id="@+id/image1"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:src="@mipmap/image_address_check_select" android:src="@mipmap/image_address_check_narmal"
></com.ck.ckcollar.app.widget.CKImageView> ></com.ck.ckcollar.app.widget.CKImageView>
</com.ck.ckcollar.app.widget.CKLinearLayout> </com.ck.ckcollar.app.widget.CKLinearLayout>

View File

@@ -14,12 +14,27 @@
android:padding="20dp" android:padding="20dp"
> >
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView" android:id="@+id/recyclerView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" />
<RelativeLayout
android:id="@+id/rel_noresult"
android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_weight="1" android:visibility="gone">
></androidx.recyclerview.widget.RecyclerView>
<include
android:id="@+id/include_noresult"
layout="@layout/include_no_result_layout" />
</RelativeLayout>
</FrameLayout>
<com.ck.ckcollar.app.widget.CKButton <com.ck.ckcollar.app.widget.CKButton

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