Compare commits

...

30 Commits

Author SHA1 Message Date
bb5bd7adf3 paypal支付账号信息的展示 2026-06-09 17:05:44 +08:00
yezhiqiu
f3ccb1f4ec 1.移除READ_MEDIA_VIDEO 权限
2.移除READ_MEDIA_IMAGES 权限,选择照片改用谷歌官方Photo picker
2026-06-02 16:39:39 +08:00
yezhiqiu
c0ab984a83 1.修复添加wifi zone提示页,提示靠近设备的弹窗,有时会弹出了两次bug
2.限制用户名空格和14个字母,7个中文输入
3.限制围栏名和wifi名空格和14个字母,7个中文输入
2026-05-29 11:13:58 +08:00
yezhiqiu
fde637793e 1.处理轨迹经纬度飘和圆滑度
2.增加围栏缩放最小值提示
3.增加map和直播显示多宠物设置
2026-05-28 11:01:51 +08:00
yezhiqiu
f26e3545b2 优化未设置wifi弹窗文案和帮助页面文案排版 2026-05-25 09:44:46 +08:00
yezhiqiu
462629386e 1.优化判断固件升级方法:改为从位依次判断
2.修复别的页面(非map页)未设置wifi宠物切换已设置wifi宠物,会出现未设置wifi弹窗bug
3.优化部分文案显示
2026-05-22 15:31:08 +08:00
yezhiqiu
63edcb7a5b 新增启动APP,wifi zone 未设置时,弹窗提示 2026-05-21 09:52:20 +08:00
yezhiqiu
bdff8cc351 新增启动APP,连接上蓝牙检测固件新版本,弹窗提示更新并自动升级 2026-05-20 11:58:32 +08:00
yezhiqiu
4dcbc176cb 新增网络获取设备的固件版本号,并显示 2026-05-19 09:24:26 +08:00
yezhiqiu
ede190d9f3 优化头像和map宠物显示速度 2026-05-15 18:32:15 +08:00
yezhiqiu
ca554656c5 1.订阅套餐新ui:增加套餐描述;修改价格区底色;Best 用皇冠图标代替;
2.新增Initializing Device界面
3.校对新增多语言字符
2026-05-14 17:14:58 +08:00
yezhiqiu
46c0a5b2a4 1. wifi zone定位点设置,改为拖动地图设置
2.添加被绑定设备增加提示被绑定的邮箱
2026-05-11 17:04:05 +08:00
yezhiqiu
0654ec87bc 1.修复位置滞后时间与上报时间重叠问题
2.宠物名称限制字数-限制为16个字符长度(中文为8个字)
3.优化添加和编辑wifi,按钮操作过程中禁止点击其他按钮
4.优化运动超过运动目标后,显示指定的百分比,取消最大值为100%
5.优化宠物和手机位置直线虚线默认显示改为默认不显示
6.修复打开邀请家人页面,切换到其它应用再切换回来,左上角返回按钮错位问题
2026-05-11 09:53:49 +08:00
yezhiqiu
5be446af72 1.map和直播页增加用户和宠物虚线设置
2.优化帮助页面
3.支付页面去掉税的计算
4.GPS: Off 改为GPS: Sleep;
5.map页增加位置更新时间格式:当更新滞后超过2倍的上报间隔时,才显示
(2h 35m ago)”,显示休眠中时,不显示“(2h 35m ago)
6.运动数据改为查看30天数据
7.历史轨迹限制只能看30天数据
2026-05-07 12:02:55 +08:00
yezhiqiu
587697954d 1.修复充电中,Map 显示Off, 但设备管理中显示Strong signal bug
2.修复GPS 没信号还是为绿点bug
3.超过30天后,退款按钮呈灰色不可点,点击后提示“Refund period has expired”,续订订单不显示按钮
4.历史订单列表页,增加退款说明
2026-04-29 10:27:29 +08:00
yezhiqiu
8d1a44bf89 1.优化区分信号弱/无信号(4种状态:1. wifi zone 中/关机/休眠/充电/超时无上报-关,2. 信号大于50-强,信号大于0小于50 -弱,3. 信号等于0-无)
2.修复围栏编辑和添加保存时/删除时,还可以输入内容和点‘取消’按钮
3.修复删除围栏时,还可以点击编辑按钮
4.修复轨迹页面围栏名字太长,列表对不齐
5.修复轨迹只有3个点时,滑块滑不动的bug
6.修复直播页面第三个导航无法点击bug
7.校对多语言字符
2026-04-24 18:55:38 +08:00
yezhiqiu
505a0414b8 适配部分机型还会出现输入框被键盘挡住问题 2026-04-24 10:29:15 +08:00
yezhiqiu
fa5b707c22 1.在解绑提示页面,增加提示语“Auto-Renew: Cancel”
2.适配Google Play 要求支持 16 KB 的内存页面大小,更新大部分第三方库到最新版本
2026-04-21 18:00:06 +08:00
yezhiqiu
4547f844ba 1.在解绑提示页面,增加提示语“Auto-Renew: Cancel”
2.适配Google Play 要求支持 16 KB 的内存页面大小,更新大部分第三方库到最新版本
2026-04-21 17:20:28 +08:00
yezhiqiu
0dfc082f2b 1.无上报的判断时间,改为动态时间,按用户所设的上报间隔的2倍计算时长
2.修改历史订单包括自动订阅订单
2026-04-20 15:32:29 +08:00
yezhiqiu
bcf03fa149 优化route页交互体验,修复有无数据切换布局错位bug 2026-04-17 15:59:35 +08:00
yezhiqiu
4e46370ec1 优化route页交互体验,修复有无数据切换布局错位bug 2026-04-17 15:43:29 +08:00
yezhiqiu
3b55eaabf4 自动订阅的套餐列表,不显示倒计时,取消自动订阅的套餐才显示 2026-04-16 18:17:46 +08:00
yezhiqiu
1325892780 自动订阅的套餐列表,不显示倒计时,取消自动订阅的套餐才显示 2026-04-16 14:58:00 +08:00
yezhiqiu
06bf4687fe 1.增加g40固件升级
2.优化dfu弹窗布局
2026-04-16 10:42:38 +08:00
yezhiqiu
d8ab8599da 时间统一格式 2026-04-15 11:51:38 +08:00
yezhiqiu
d002310a0d 1.增加G40蓝牙日志上报 2026-04-15 10:36:11 +08:00
yezhiqiu
69aa917897 1.route页ui功能改版 2026-04-14 17:10:34 +08:00
yezhiqiu
20ff76b933 1.新增wifi列表g40根据手机系统wifi来显示wifi名字
2.新增map页地址显示当前wifizone名字
2026-04-09 15:44:08 +08:00
yezhiqiu
862c9c9a06 1.增加默认谷歌地图导航
2.优化人和宠物位置切换
2026-04-09 09:47:27 +08:00
292 changed files with 6167 additions and 1425 deletions

View File

@@ -4,10 +4,10 @@
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2026-04-01T06:06:01.472811800Z">
<DropdownSelection timestamp="2026-06-01T08:32:46.679728300Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="PhysicalDevice" identifier="serial=3A040DLJH000R0" />
<DeviceId pluginId="PhysicalDevice" identifier="serial=GBG5T19625003301" />
</handle>
</Target>
</DropdownSelection>

2
.idea/gradle.xml generated
View File

@@ -6,7 +6,7 @@
<GradleProjectSettings>
<option name="testRunner" value="CHOOSE_PER_TEST" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="jbr-21" />
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />

View File

@@ -1 +0,0 @@
o/bundleLibRuntimeToDirDebug

View File

@@ -1 +1 @@
#Thu Mar 19 17:33:53 CST 2026
#Thu Jun 04 09:43:21 CST 2026

View File

@@ -28,9 +28,9 @@ android {
applicationId "com.abbidot.tracker"
minSdkVersion 23
targetSdkVersion 35
versionCode 2112
versionName "2.1.12"
// versionName "2.1.12-Beta4"
versionCode 2210
// versionName "2.2.10"
versionName "2.2.10-Beta2"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@@ -63,6 +63,17 @@ android {
]
}
//解决mapBox和百度地图libc++_shared.so发生冲突http://www.52im.net/blog-28523-2848.html
packagingOptions {
pickFirst 'lib/x86/libc++_shared.so'
pickFirst 'lib/x86_64/libc++_shared.so'
pickFirst 'lib/armeabi-v7a/libc++_shared.so'
pickFirst 'lib/arm64-v8a/libc++_shared.so'
pickFirst 'lib/armeabi/libc++_shared.so'
pickFirst 'lib/mips/libc++_shared.so'
pickFirst 'lib/mips64/libc++_shared.so'
}
// 读取local.properties文件
Properties properties = new Properties()
InputStream inputStream = project.rootProject.file('local.properties').newDataInputStream()
@@ -182,29 +193,32 @@ dependencies {
// implementation 'com.google.android.material:material:1.10.0'
// implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.10.0'
implementation 'androidx.activity:activity:1.8.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.2.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
// Android官方库
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.constraintlayout:constraintlayout:2.2.1'
implementation 'androidx.arch.core:core-common:2.2.0'
implementation 'androidx.arch.core:core-runtime:2.2.0'
implementation 'androidx.activity:activity-ktx:1.9.3'
implementation 'androidx.fragment:fragment-ktx:1.5.6'
implementation 'androidx.annotation:annotation:1.9.1'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.8.7'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.8.7'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.7'
implementation 'androidx.activity:activity-ktx:1.10.1'
implementation 'androidx.fragment:fragment-ktx:1.8.9'
implementation 'androidx.annotation:annotation:1.10.0'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.10.0'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.10.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.10.0'
implementation 'androidx.room:room-runtime:2.5.2'
implementation 'androidx.room:room-runtime:2.8.4'
// implementation 'androidx.room:room-rxjava2:2.3.0'
implementation 'androidx.room:room-ktx:2.5.2'
kapt 'androidx.room:room-compiler:2.5.2'
implementation 'androidx.room:room-ktx:2.8.4'
kapt 'androidx.room:room-compiler:2.8.4'
//hilt依赖注入https://mvnrepository.com/artifact/com.google.dagger/hilt-android-gradle-plugin
implementation "com.google.dagger:hilt-android:2.57"
kapt "com.google.dagger:hilt-android-compiler:2.57"
implementation "com.google.dagger:hilt-android:2.57.2"
kapt "com.google.dagger:hilt-android-compiler:2.57.2"
//Android UI 开发效率的 UI 库https://github.com/Tencent/QMUI_Android
implementation 'com.qmuiteam:qmui:2.1.0'
@@ -221,11 +235,11 @@ dependencies {
implementation "io.coil-kt:coil-gif:1.4.0"//支持GIF
//lottie动画https://github.com/airbnb/lottie-android
implementation 'com.airbnb.android:lottie:6.6.7'
implementation 'com.airbnb.android:lottie:6.7.1'
//https://github.com/CymChad/BaseRecyclerViewAdapterHelper
implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.11'
implementation "io.github.cymchad:BaseRecyclerViewAdapterHelper:3.0.14"
//升级recyclerview因BaseRecyclerViewAdapterHelper item点击事件是使用1.2.0
implementation 'androidx.recyclerview:recyclerview:1.3.1'
implementation 'androidx.recyclerview:recyclerview:1.4.0'
//谷歌地图
implementation 'com.google.android.gms:play-services-maps:20.0.0'
@@ -245,21 +259,24 @@ dependencies {
//mapbox地图https://github.com/mapbox/mapbox-maps-android
// implementation 'com.mapbox.maps:android:10.2.0'
//https://github.com/mapbox/mapbox-search-android
//用mapbox搜索SDK,地理编码 有搜索ui组件已包括mapbox-search-android架包
implementation "com.mapbox.search:mapbox-search-android-ui:2.5.1"
/**用mapbox搜索SDK,地理编码 有搜索ui组件已包括mapbox-search-android架包
* 支持 16 KB 页面大小
* https://docs.mapbox.com/android/search/guides/install/#step-2-add-search-sdk-dependencies
*/
implementation "com.mapbox.search:mapbox-search-android-ui-ndk27:2.22.0"
// mapbox搜索SDK,地理编码 没有搜索ui组件
// implementation "com.mapbox.search:mapbox-search-android:1.0.0-beta.25"
//用于计算距离https://docs.mapbox.com/android/java/guides/turf/#available-methods
implementation 'com.mapbox.mapboxsdk:mapbox-sdk-turf:6.15.0'
//用于计算路线规划信息https://docs.mapbox.com/android/java/examples/dashed-directions-line/
implementation 'com.mapbox.mapboxsdk:mapbox-sdk-services:6.3.0'
//用于计算距离https://docs.mapbox.com/android/java/guides/#installation
implementation 'com.mapbox.mapboxsdk:mapbox-sdk-turf:7.10.0'
//用于计算路线规划信息、地理编码
implementation 'com.mapbox.mapboxsdk:mapbox-sdk-services:7.10.0'
// 权限请求框架https://github.com/getActivity/XXPermissions
implementation 'com.github.getActivity:XXPermissions:25.2'
implementation 'com.github.getActivity:XXPermissions:28.2'
// 吐司框架https://github.com/getActivity/ToastUtils
implementation 'com.github.getActivity:Toaster:13.2'
implementation 'com.github.getActivity:Toaster:15.0'
// 日志调试框架https://github.com/getActivity/Logcat ,在debug模式下集成
debugImplementation 'com.github.getActivity:Logcat:12.3'
debugImplementation 'com.github.getActivity:Logcat:13.0'
// PictureSelector图片选择器,需要compileSdkVersion=31 https://github.com/LuckSiege/PictureSelector
// implementation 'io.github.lucksiege:pictureselector:v3.0.3'
@@ -268,14 +285,14 @@ dependencies {
//压缩图片 https://github.com/zetbaitsu/Compressor
implementation 'id.zelory:compressor:3.0.1'
//图片裁剪功能https://github.com/CanHub/Android-Image-Cropper
implementation 'com.vanniktech:android-image-cropper:4.6.0'
implementation 'com.vanniktech:android-image-cropper:4.7.0'
//******************************************极光推送start*****************************************************
// https://docs.jiguang.cn/jpush/client/Android/android_guide
// implementation 'cn.jiguang.sdk:jcore:3.1.2' // 此处以JCore 2.7.2 版本为例。
// implementation 'cn.jiguang.sdk:jpush:4.6.0' // 此处以JPush 4.0.0 版本为例
implementation 'cn.jiguang.sdk:jcore-google:5.1.0' // 此处以JCore 2.7.2 版本为例。
implementation 'cn.jiguang.sdk:jpush-google:5.8.0' // 此处以JPush 4.0.0 版本为例
implementation 'cn.jiguang.sdk:jcore-google:5.3.7' // 此处以JCore 2.7.2 版本为例。
implementation 'cn.jiguang.sdk:jpush-google:6.0.7' // 此处以JPush 4.0.0 版本为例
// 接入华为厂商
// implementation 'com.huawei.hms:push:6.1.0.300'
// implementation 'cn.jiguang.sdk.plugin:huawei:4.0.0'// 极光厂商插件版本与接入 JPush 版本保持一致,下同
@@ -294,7 +311,7 @@ dependencies {
//******************************************极光推送end*******************************************************
//其中指代最新Bugly SDK版本号也可以指定明确的版本号例如4.0.0
implementation 'com.tencent.bugly:crashreport:4.1.9.3'
// implementation 'com.tencent.bugly:crashreport:4.1.9.3'
//其中latest.release指代最新Bugly NDK版本号也可以指定明确的版本号例如3.9.2
// implementation 'com.tencent.bugly:nativecrashreport:3.9.2'
@@ -306,24 +323,27 @@ dependencies {
implementation 'com.stripe:stripe-android:20.27.0'
//百度地图基础定位组件
implementation 'com.baidu.lbsyun:BaiduMapSDK_Location:9.6.5.1'
implementation 'com.baidu.lbsyun:BaiduMapSDK_Location:9.6.7'
//地图组件
implementation 'com.baidu.lbsyun:BaiduMapSDK_Map:7.5.2'
implementation 'com.baidu.lbsyun:BaiduMapSDK_Map:7.6.7'
//检索组件
implementation 'com.baidu.lbsyun:BaiduMapSDK_Search:7.5.2'
implementation 'com.baidu.lbsyun:BaiduMapSDK_Search:7.6.7'
//工具组件
implementation 'com.baidu.lbsyun:BaiduMapSDK_Util:7.5.2'
implementation 'com.baidu.lbsyun:BaiduMapSDK_Util:7.6.7'
//微信登录、支付
implementation 'com.tencent.mm.opensdk:wechat-sdk-android:+'
//支付宝支付
implementation 'com.alipay.sdk:alipaysdk-android:+@aar'
//dfu升级https://github.com/NordicSemiconductor/Android-DFU-Library
implementation 'no.nordicsemi.android:dfu:2.9.0'
//g30 dfu升级https://github.com/NordicSemiconductor/Android-DFU-Library
implementation 'no.nordicsemi.android:dfu:2.10.1'
//g40 dfu升级https://github.com/nordicsemi/Android-nRF-Connect-Device-Manager?tab=readme-ov-file#migration-from-the-original-repo
// implementation 'no.nordicsemi.android:mcumgr-core:2.7.4'
implementation 'no.nordicsemi.android:mcumgr-ble:2.7.4'
//适配Android 12以下SplashScreen启动动画闪屏图片
implementation 'androidx.core:core-splashscreen:1.0.1'
implementation 'androidx.core:core-splashscreen:1.2.0'
//优雅、万能自定义日历https://github.com/huanghaibin-dev/CalendarView
// implementation 'com.haibin:calendarview:3.7.1'
//https://github.com/angcyo/CalendarView

View File

@@ -38,6 +38,7 @@
<uses-permission
android:name="android.permission.WRITE_SETTINGS"
tools:ignore="ProtectedPermissions" /> <!-- android 9.0上使用前台服务,需要添加权限 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- BLUETOOTH permissions are added by lib_dfu module. -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- 用于读取手机当前的状态 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" /> <!-- 读取缓存数据 -->
<!-- 蓝牙扫描权限 -->
@@ -55,7 +56,6 @@
android:protectionLevel="signature" /> <!-- Optional. Required for location feature -->
<uses-permission android:name="${applicationId}.permission.JPUSH_MESSAGE" /> <!-- 为了提高sdk识别唯一用户的能力保证消息推送的精准送达建议集成以下权限可选 -->
<!-- <uses-permission -->
<!-- android:name="android.permission.QUERY_ALL_PACKAGES" -->
<!-- tools:ignore="QueryAllPackagesPermission" /> -->
<!-- 如您需要接入地理围栏业务,建议集成以下权限(可选) -->
<uses-permission android:name="android.permission.GET_TASKS" /> <!-- 如您需要对应设备通知相关的能力,建议集成以下权限(可选) -->
@@ -77,17 +77,17 @@
<uses-permission
android:name="android.permission.REQUEST_INSTALL_PACKAGES"
tools:node="remove" /> <!-- Android 13上一新增运行时权限 -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <!-- 通知权限 -->
<!-- <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> -->
<!-- <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> -->
<!-- <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> -->
<!-- 通知权限 -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" /> <!-- Android 12新增权限适配 -->
<uses-permission
android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation"
tools:targetApi="s" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <!-- BLUETOOTH permissions are added by lib_dfu module. -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE" /> <!-- 指定微信包名 -->
<queries>
<package android:name="com.tencent.mm" />
@@ -106,6 +106,15 @@
android:usesCleartextTraffic="true"
tools:replace="android:supportsRtl"
tools:targetApi="n">
<activity
android:name=".ui.activity.account.cn.LoginV2CNActivity"
android:exported="false" />
<activity
android:name=".deprecated.ui.activity.profile.recharge.cn.RechargeOrderDetailCNActivity"
android:exported="false" />
<activity
android:name=".ui.activity.device.InitializingDeviceActivity"
android:exported="false" />
<activity
android:name=".ui.activity.device.set.PowerOffActivity"
android:exported="false"
@@ -386,7 +395,8 @@
<activity
android:name=".ui.activity.device.wifi.EditWifiPowerZoneActivity"
android:exported="false"
android:screenOrientation="portrait" />
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustPan" />
<activity
android:name=".ui.activity.map.LiveActivityV3"
android:exported="false"
@@ -417,9 +427,6 @@
<activity
android:name=".ui.activity.account.recharge.cn.RechargeDeviceDetailCNActivity"
android:screenOrientation="portrait" />
<activity
android:name=".ui.activity.account.recharge.cn.RechargeOrderDetailCNActivity"
android:screenOrientation="portrait" />
<activity
android:name=".ui.activity.account.recharge.cn.RechargeAmountCNActivity"
android:screenOrientation="portrait" />

View File

@@ -2,19 +2,50 @@
<body>
<div>
<h3>ABBIDOT Tracker Subscription Terms and Conditions
</h3>
<p>1.Subscription Plans Users can choose between Basic and Prime plans. Basic plan subscribers can upgrade to Prime at any time. Prime plan subscribers can't change to Basic plan.
<p>2.Refund Policy Automatic Refund (Within 48 Hours): Full refund available if canceled within 48 hours of subscription. Processed automatically without manual review. Manual Refund (After 48 Hours): For subscriptions older than 48 hours but within 1 month, refunds require manual approval. Eligibility: Only applicable to annual (1-year) subscriptions. Refunds may be prorated based on usage. No Refund After 1 Month: Subscriptions active for over 1 month are non-refundable.</p>
<p>3.Pausing Subscription & Number Retention Users may pause their subscription. Number Retention: Paused numbers can be retained for up to 1 year. A small fee will apply for number retention during the pause period. Failure to reactivate within 1 year may result in number release.</p>
<p>4.Modifications ABBIDOT reserves the right to update these terms. Users will be notified of changes. By subscribing, you agree to these terms.</p>
<p>For support contact:</p>
<p>support@abbidot.com</p>
<h2>ABBIDOT Tracker Subscription Terms and Conditions</h2>
<hr>
<h3>1. Subscription Plans</h3>
<p>ABBIDOT offers three subscription plans:</p>
<ul>
<li>3-Month Plan</li>
<li>1-Year Plan</li>
<li>2-Year Plan</li>
</ul>
<p>All subscriptions are automatically renewed at the end of each billing cycle unless canceled by the user.</p>
<p>Users may cancel their subscription at any time. After cancellation, the subscription will remain active until the end of the current billing period, and no further charges will be applied.</p>
<p>The device will continue to function normally during the active subscription period.</p>
<hr>
<h3>2. Refund Policy</h3>
<h4>2.1 Automatic Refund (Within 48 Hours)</h4>
<p>All subscription purchases are eligible for a <strong>full automatic refund within 48 hours</strong> of payment. Refunds will be processed automatically without manual review.</p>
<hr>
<h4>2.2 Standard Refund Window (30 Days)</h4>
<p>After the initial 48-hour period, users may request a refund within <strong>30 days of purchase.</strong></p>
<ul>
<li>All subscription plans (3-Month, 1-Year, 2-Year) are eligible</li>
<li>Refund requests are subject to review and approval</li>
<li>Refunds may be partially adjusted based on usage and service consumption</li>
</ul>
<hr>
<h4>2.3 No Refund After 30 Days</h4>
<p>Subscriptions older than 30 days are non-refundable.</p>
<hr>
<h3>3. Subscription Cancellation</h3>
<p>Users may cancel their subscription at any time.</p>
<ul>
<li>Cancellation stops future billing</li>
<li>The current subscription remains active until the end of the billing period</li>
<li>No partial refund is issued after cancellation unless within the refund window</li>
</ul>
<hr>
<h3>4. Policy Updates</h3>
<p>ABBIDOT reserves the right to update or modify these Terms and Conditions at any time. Users will be notified of significant changes.</p>
<p>By subscribing to ABBIDOT services, you agree to these terms.</p>
<hr>
<h3>5. Customer Support</h3>
<p>If you encounter any difficulties, please contact us at:</p>
<p><a title="Mail to subscription@abbidot.com" href="subscription@abbidot.com">subscription@abbidot.com</a></p>
<p>Our support team will assist you as soon as possible.</p>
</div>

View File

@@ -27,6 +27,9 @@ class MyApplication : Application() {
companion object {
lateinit var instance: Application
//保存地图宠物头像对象在内存中,提高显示速度
val mapPetHeadHashMap = hashMapOf<String, Any>()
}
override fun onCreate() {

View File

@@ -40,7 +40,9 @@ class AssignOptionsAdapter(
} else {
circleImageView.visibility = View.VISIBLE
wrapImageView.visibility = View.GONE
ViewUtil.instance.setPetTypeHead(circleImageView, item.value, item.menuType)
ViewUtil.instance.setPetTypeHead(
mContext, circleImageView, item.value, item.menuType
)
}
}
}

View File

@@ -38,7 +38,7 @@ class ChangePetListDialogAdapter(ctx: Context, list: MutableList<PetBean>?) :
holder.setText(R.id.dialog_my_pet_name, item.petName)
holder.getImageView(R.id.dialog_my_pet_head).apply {
ViewUtil.instance.setPetTypeHead(this, item.imgurl, item.petType)
ViewUtil.instance.setPetTypeHead(mContext,this, item.imgurl, item.petType)
setOnClickListener {
if (null != mOnChangeClickListener) {
mOnChangeClickListener!!.onCurrentClick()

View File

@@ -1,7 +1,11 @@
package com.abbidot.tracker.adapter
import android.content.Context
import android.content.res.ColorStateList
import android.text.TextUtils
import android.view.View
import androidx.core.content.ContextCompat
import androidx.core.graphics.toColorInt
import com.abbidot.baselibrary.list.BaseRecyclerAdapter
import com.abbidot.baselibrary.list.RecyclerViewHolder
import com.abbidot.baselibrary.util.Utils
@@ -9,6 +13,8 @@ import com.abbidot.tracker.R
import com.abbidot.tracker.bean.PackageBean
import com.abbidot.tracker.constant.ConstantInt
import com.abbidot.tracker.constant.ConstantString
import com.qmuiteam.qmui.widget.roundwidget.QMUIRoundButtonDrawable
import com.qmuiteam.qmui.widget.roundwidget.QMUIRoundRelativeLayout
/**
*Created by .yzq on 2024/8/6/006.
@@ -51,6 +57,10 @@ class ChoosePlanAdapter(
getView(R.id.ll_choose_plan_item_discount_percent).let {
it.visibility = if (item.popularType == ConstantInt.Type1) View.INVISIBLE
else View.INVISIBLE
}
getView(R.id.iv_choose_plan_item_popular_image).let {
it.visibility = if (item.popularType == ConstantInt.Type1) View.VISIBLE
else View.INVISIBLE
}
@@ -62,6 +72,44 @@ class ChoosePlanAdapter(
if (item.popularType == ConstantInt.Type1) it.visibility = View.GONE
else it.visibility = View.GONE
}
(getView(R.id.rl_choose_plan_item_price) as QMUIRoundRelativeLayout).let {
(it.background as QMUIRoundButtonDrawable).let { drawable ->
val bgColor = if (TextUtils.isEmpty(item.bottomBgColor)) {
ContextCompat.getColor(mContext, R.color.tracker_manage_bg_color)
} else {
item.bottomBgColor.toColorInt()
}
drawable.setBgData(ColorStateList.valueOf(bgColor))
}
}
getTextView(R.id.tv_choose_plan_item_power).let {
it.visibility = if (item.list.isNullOrEmpty()) View.GONE
else {
var str = getManyLanguageLimitDec(item.listTitleCode)
if (TextUtils.isEmpty(str)) {
for (i in 0 until item.list!!.size) {
val packageDec = item.list!![i]
str += "${i + 1}.${packageDec.title}"
if (i != item.list!!.size - 1) {
str += "\n"
}
}
}
it.text = str
View.VISIBLE
}
}
}
}
private fun getManyLanguageLimitDec(nameCode: Int): String {
return when (nameCode) {
ConstantInt.Type1 -> mContext.getString(R.string.txt_package_permission1)
ConstantInt.Type2 -> mContext.getString(R.string.txt_package_permission2)
ConstantInt.Type3 -> mContext.getString(R.string.txt_package_permission3)
else -> ""
}
}
}

View File

@@ -1,12 +1,13 @@
package com.abbidot.tracker.adapter
import android.graphics.Typeface
import android.widget.ImageView
import android.util.TypedValue
import androidx.appcompat.widget.AppCompatImageView
import androidx.core.content.ContextCompat
import com.abbidot.baselibrary.util.AppUtils
import com.abbidot.tracker.R
import com.abbidot.tracker.bean.MenuTxtBean
import com.abbidot.tracker.constant.ConstantInt
import com.abbidot.tracker.constant.MultipleEntity
import com.abbidot.tracker.widget.TypefaceTextView
import com.chad.library.adapter.base.BaseMultiItemQuickAdapter
@@ -32,6 +33,8 @@ class HelpTextImageTypeAdapter(list: MutableList<MenuTxtBean>?) :
addItemType(MultipleEntity.IMG_IMG, R.layout.layout_help_title1)
//显示14sp大小的文字内容
addItemType(MultipleEntity.IMG_TEXT_IMG, R.layout.layout_help_title2)
//显示多大字体,是否粗体,字体颜色
addItemType(MultipleEntity.TEXT_TEXT_IMG, R.layout.layout_help_title2)
}
override fun convert(holder: BaseViewHolder, item: MenuTxtBean) {
@@ -67,6 +70,23 @@ class HelpTextImageTypeAdapter(list: MutableList<MenuTxtBean>?) :
holder.getView<TypefaceTextView>(R.id.tv_help_title_two).text = item.menuName
holder.itemView.setPadding(0, AppUtils.dpToPx(14), 0, 0)
}
MultipleEntity.TEXT_TEXT_IMG -> {
holder.getView<TypefaceTextView>(R.id.tv_help_title_two).apply {
//是否粗体
val typefaceBold =
if (item.isSwitch) Typeface.create(Typeface.DEFAULT, Typeface.BOLD)
else Typeface.create(Typeface.DEFAULT, Typeface.NORMAL)
typeface = typefaceBold
text = item.menuName
setTextSize(TypedValue.COMPLEX_UNIT_SP, item.state.toFloat())
val tColor = if (item.colorRedId == ConstantInt.Type0) R.color.data_black_color
else item.colorRedId
setTextColor(ContextCompat.getColor(context, tColor))
}
// holder.itemView.setPadding(0, AppUtils.dpToPx(14), 0, 0)
}
}
}

View File

@@ -0,0 +1,67 @@
package com.abbidot.tracker.adapter
import android.content.Context
import android.text.format.DateUtils
import android.view.View
import com.abbidot.baselibrary.list.BaseRecyclerAdapter
import com.abbidot.baselibrary.list.RecyclerViewHolder
import com.abbidot.baselibrary.util.Utils
import com.abbidot.tracker.R
import com.abbidot.tracker.bean.MessageBean
import com.abbidot.tracker.constant.ConstantInt
/**
*Created by .yzq on 2026/4/10/周五.
* @link
* @description:
*/
class HistoryFenceAdapter(
ctx: Context, list: MutableList<MessageBean>?
) : BaseRecyclerAdapter<MessageBean>(ctx, list) {
override fun getEmptyLayoutId(viewType: Int) = 0
override fun getItemLayoutId(viewType: Int) = R.layout.item_history_fence_layout
override fun bindData(holder: RecyclerViewHolder?, position: Int, item: MessageBean) {
holder?.apply {
getImageView(R.id.iv_history_fence_type_image).let {
when (item.deviceMessageType) {
ConstantInt.Type1, ConstantInt.Type3 -> it.setImageResource(R.drawable.icon_history_danger_fence_image)
ConstantInt.Type2 -> it.setImageResource(R.drawable.icon_history_save_fence_image)
ConstantInt.Type4 -> it.setImageResource(R.drawable.icon_history_no_save_fence_image)
}
}
getTextView(R.id.tv_history_fence_type_time).text =
getRelativeTimeString(item.timeStamp)
getTextView(R.id.tv_history_fence_type_content).text = item.message
getImageView(R.id.iv_history_fence_type_line).let {
it.visibility = if (position == getData().size - 1) View.GONE
else View.VISIBLE
}
}
}
private fun getRelativeTimeString(timeStamp: Long): String {
val formatDateStr: String
val cTimeStamp = Utils.stringToTimestamp(
Utils.formatTime(
timeStamp, Utils.DATE_FORMAT_PATTERN_CN2
)
)
val now = System.currentTimeMillis()
formatDateStr = if (DateUtils.isToday(cTimeStamp)) {
mContext.getString(R.string.txt_today) + " " + Utils.formatTime(
timeStamp, Utils.DATE_FORMAT_PATTERN_EN14
)
} else if (now - cTimeStamp < (48 * 60 * 60 * 1000)) {
mContext.getString(R.string.txt_yesterday) + " " + Utils.formatTime(
timeStamp, Utils.DATE_FORMAT_PATTERN_EN14
)
} else {
Utils.formatTime(
timeStamp, Utils.DATE_FORMAT_PATTERN_EN15
)
}
return formatDateStr
}
}

View File

@@ -80,7 +80,7 @@ class MySubscriptionAdapter(
}
holder.setText(
R.id.tv_my_subscription_active_time,
Utils.formatTime(item.payTime, Utils.DATE_FORMAT_PATTERN_EN6)
Utils.formatTime(item.payTime, Utils.DATE_FORMAT_PATTERN_CN4)
)
holder.getTextView(R.id.tv_my_subscription_annual_care).apply {
@@ -91,12 +91,12 @@ class MySubscriptionAdapter(
holder.getTextView(R.id.tv_my_subscription_expires_on).apply {
text = if (item.orderStatus == 6 && item.refundTime > 0L) {
Utils.formatTime(item.refundTime, Utils.DATE_FORMAT_PATTERN_EN6)
Utils.formatTime(item.refundTime, Utils.DATE_FORMAT_PATTERN_CN4)
} else {
Utils.formatTime(
Utils.timestampAddHowTimestamp(
item.payTime, item.mealPeriod, item.mealUnit
), Utils.DATE_FORMAT_PATTERN_EN7
), Utils.DATE_FORMAT_PATTERN_CN
)
}
}
@@ -147,9 +147,27 @@ class MySubscriptionAdapter(
}
val times = Utils.differYear(cTimeMillis, item.endTime)
holder.setText(R.id.tv_add_success_device_expires_days, times[0])
holder.setText(R.id.tv_add_success_device_expires_hours, times[1])
holder.setText(R.id.tv_add_success_device_expires_min, times[2])
holder.getTextView(R.id.tv_add_success_device_expires_days).apply {
visibility = if (item.subscriptionStatus == ConstantInt.Close) {
text = times[0]
View.VISIBLE
} else View.GONE
holder.getTextView(R.id.tv_add_device_expires_year_title).visibility = visibility
}
holder.getTextView(R.id.tv_add_success_device_expires_hours).apply {
visibility = if (item.subscriptionStatus == ConstantInt.Close) {
text = times[1]
View.VISIBLE
} else View.GONE
holder.getTextView(R.id.tv_add_device_expires_month_title).visibility = visibility
}
holder.getTextView(R.id.tv_add_success_device_expires_min).apply {
visibility = if (item.subscriptionStatus == ConstantInt.Close) {
text = times[2]
View.VISIBLE
} else View.GONE
holder.getTextView(R.id.tv_add_device_expires_day_title).visibility = visibility
}
holder.getView(R.id.fl_my_subscription_btn_layout).apply {
//UserId不一样就是共享设备的订单
@@ -187,7 +205,7 @@ class MySubscriptionAdapter(
setOnClickListener {
qMUIPopups.dismiss()
Intent(mContext, SubscriptionHistoryActivity::class.java).let {
it.putExtra(ConstantString.DeviceId, item.deviceId)
it.putExtra(ConstantString.Id, item.subscriptionId)
mMySubscriptionActivity.startActivity(it)
}
}

View File

@@ -116,7 +116,7 @@ class MyTrackerV2Adapter(
petName.visibility = View.VISIBLE
item.pet?.let {
petName.text = it.petName
ViewUtil.instance.setPetTypeHead(petHead, it.imgurl, it.petType)
ViewUtil.instance.setPetTypeHead(mContext, petHead, it.imgurl, it.petType)
}
}
}

View File

@@ -58,7 +58,7 @@ class NotificationV2Adapter(
}
private fun getRelativeTimeString(timeStamp: Long): String {
var formatDateStr = ""
val formatDateStr: String
val cTimeStamp = Utils.stringToTimestamp(
Utils.formatTime(
timeStamp, Utils.DATE_FORMAT_PATTERN_CN2
@@ -67,15 +67,15 @@ class NotificationV2Adapter(
val now = System.currentTimeMillis()
formatDateStr = if (DateUtils.isToday(cTimeStamp)) {
mContext.getString(R.string.txt_today) + " " + Utils.formatTime(
timeStamp, Utils.DATE_FORMAT_PATTERN_EN8
timeStamp, Utils.DATE_FORMAT_PATTERN_EN14
)
} else if (now - cTimeStamp < (48 * 60 * 60 * 1000)) {
mContext.getString(R.string.txt_yesterday) + " " + Utils.formatTime(
timeStamp, Utils.DATE_FORMAT_PATTERN_EN8
timeStamp, Utils.DATE_FORMAT_PATTERN_EN14
)
} else {
Utils.formatTime(
timeStamp, Utils.DATE_FORMAT_PATTERN_EN9
timeStamp, Utils.DATE_FORMAT_PATTERN_CN2
)
}
return formatDateStr

View File

@@ -1,5 +1,6 @@
package com.abbidot.tracker.adapter
import android.content.Context
import android.content.Intent
import android.view.View
import android.widget.TextView
@@ -16,6 +17,8 @@ import com.abbidot.tracker.ui.activity.subscribe.SubscriptionHistoryActivity
import com.abbidot.tracker.widget.TypefaceRoundButton
import com.chad.library.adapter.base.BaseMultiItemQuickAdapter
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.hjq.toast.Toaster
import com.qmuiteam.qmui.widget.roundwidget.QMUIRoundButtonDrawable
/**
*Created by .yzq on 2024/8/19/019.
@@ -46,6 +49,9 @@ class SubscriptionHistoryAdapter(
}
}
/**
* 保险订单
*/
private fun bindAnnualCareData(holder: BaseViewHolder, item: SubscriptionsOrderBean) {
holder.setText(
R.id.tv_subscription_annual_care_order_id,
@@ -63,7 +69,7 @@ class SubscriptionHistoryAdapter(
holder.setText(R.id.tv_subscription_annual_care_state, state)
holder.setText(
R.id.tv_subscription_annual_care_active_time, Utils.formatTime(
item.payTime, Utils.DATE_FORMAT_PATTERN_EN7
item.payTime, Utils.DATE_FORMAT_PATTERN_CN
)
)
//保险时长不足一年按12个月算
@@ -73,7 +79,7 @@ class SubscriptionHistoryAdapter(
R.id.tv_subscription_annual_care_expiry_time, Utils.formatTime(
Utils.timestampAddHowTimestamp(
item.payTime, insuranceTime, ConstantString.PackageUnitYear
), Utils.DATE_FORMAT_PATTERN_EN7
), Utils.DATE_FORMAT_PATTERN_CN
)
)
holder.setText(
@@ -93,7 +99,7 @@ class SubscriptionHistoryAdapter(
)
holder.setText(
R.id.tv_subscription_history_order_time,
Utils.formatTime(item.payTime, Utils.DATE_FORMAT_PATTERN_EN10)
Utils.formatTime(item.payTime, Utils.DATE_FORMAT_PATTERN_CN2)
)
holder.setText(R.id.tv_subscription_history_package_name, item.mealName)
holder.setText(
@@ -111,33 +117,39 @@ class SubscriptionHistoryAdapter(
visibility = View.VISIBLE
when (item.orderStatus) {
1 -> {
val updateTimestamp = Utils.stringToTimestamp(item.updateTime, isUtc = true)
val nowTimestamp = System.currentTimeMillis()
if (item.enabled == ConstantInt.Type0 || (item.surplusDays == 0L && item.subscriptionStatus == ConstantInt.Close)) {
if (item.isAutoRenewal == ConstantInt.Type1) {
visibility = View.GONE
} else if (item.mealUnit == ConstantString.PackageUnitDay) {
visibility = View.VISIBLE
setText(R.string.txt_refund)
} else if (item.mealUnit == ConstantString.PackageUnitMonth) {
val day7Timestamp = 7 * 24 * 60 * 60 * 1000L
//套餐超出7天不能退款
if (nowTimestamp - updateTimestamp <= day7Timestamp) {
visibility = View.VISIBLE
setText(R.string.txt_refund)
} else {
visibility = View.GONE
}
} else {
val day30Timestamp = 30 * 24 * 60 * 60 * 1000L
//套餐超出30天不能退款
if (nowTimestamp - updateTimestamp <= day30Timestamp) {
visibility = View.VISIBLE
setText(R.string.txt_refund)
} else {
visibility = View.GONE
}
setRefundState(context, item.isRefundable, this)
}
setTextColor(ContextCompat.getColor(context, R.color.select_color))
// val updateTimestamp = Utils.stringToTimestamp(item.updateTime, isUtc = true)
// val nowTimestamp = System.currentTimeMillis()
// if (item.enabled == ConstantInt.Type0 || (item.surplusDays == 0L && item.subscriptionStatus == ConstantInt.Close)) {
// visibility = View.GONE
// } else if (item.mealUnit == ConstantString.PackageUnitDay) {
// visibility = View.VISIBLE
// setText(R.string.txt_refund)
// } else if (item.mealUnit == ConstantString.PackageUnitMonth) {
// val day7Timestamp = 7 * 24 * 60 * 60 * 1000L
// //套餐超出7天不能退款
// if (nowTimestamp - updateTimestamp <= day7Timestamp) {
// visibility = View.VISIBLE
// setText(R.string.txt_refund)
// } else {
// visibility = View.GONE
// }
// } else {
// val day30Timestamp = 30 * 24 * 60 * 60 * 1000L
// //套餐超出30天不能退款
// if (nowTimestamp - updateTimestamp <= day30Timestamp) {
// visibility = View.VISIBLE
// setText(R.string.txt_refund)
// } else {
// visibility = View.GONE
// }
// }
// setTextColor(ContextCompat.getColor(context, R.color.select_color))
}
4 -> setText(R.string.txt_waiting)
@@ -155,6 +167,10 @@ class SubscriptionHistoryAdapter(
setChangeAlphaWhenPress(true)
setOnClickListener {
if (item.orderStatus == ConstantInt.Type1) {
if (item.isRefundable == ConstantInt.Type0) {
Toaster.show(R.string.txt_refund_expired)
return@setOnClickListener
}
Intent(context, RequestRefundActivity::class.java).apply {
putExtra(ConstantString.SetMeal, item)
mHistoryActivity.startActivity(this)
@@ -166,12 +182,11 @@ class SubscriptionHistoryAdapter(
val cTimeMillis = System.currentTimeMillis()
val endTime = if (item.refundTime == 0L) item.endTime else item.refundTime
val expiredTime = endTime * 1000 - cTimeMillis
val state =
if (item.enabled == ConstantInt.Type0 || (item.subscriptionStatus == ConstantInt.Close && expiredTime <= 0)) {
context.getString(R.string.txt_expired)
} else {
context.getString(R.string.txt_active)
}
val state = if (item.enabled == ConstantInt.Type0 || (expiredTime <= 0)) {
context.getString(R.string.txt_expired)
} else {
context.getString(R.string.txt_active)
}
holder.setText(R.id.tv_subscription_history_subscription_state, state)
holder.getView<TextView>(R.id.tv_subscription_history_annual_care).apply {
@@ -181,4 +196,24 @@ class SubscriptionHistoryAdapter(
}
}
private fun setRefundState(
context: Context, isRefundable: Int, roundButton: TypefaceRoundButton
) {
roundButton.apply {
var textColor = R.color.select_color
val strokeColor = if (isRefundable == ConstantInt.Type1) {
R.color.block_color
} else {
textColor = R.color.line_color1
R.color.permission_no_check_color
}
(background as QMUIRoundButtonDrawable).let {
it.setStroke(
it.strokeWidth, ContextCompat.getColor(context, strokeColor)
)
}
setTextColor(ContextCompat.getColor(context, textColor))
}
}
}

View File

@@ -0,0 +1,41 @@
package com.abbidot.tracker.adapter;
import android.content.Context;
import android.view.View;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
/**
* Created by .yzq on 2026/4/13/周一.
*
* @link
* @description:
*/
public class TopSlideLayoutManager extends LinearLayoutManager {
private int mTopOffset;
public TopSlideLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
public void setTopOffset(int topOffset) {
mTopOffset = topOffset;
requestLayout();
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
super.onLayoutChildren(recycler, state);
// 可以在这里调整子项的位置,例如将顶部几个项上移
if (getChildCount() > 0) {
View firstChild = getChildAt(0);
if (firstChild != null) {
int top = getDecoratedTop(firstChild) - mTopOffset;
layoutDecoratedWithMargins(firstChild, firstChild.getLeft(), top,
firstChild.getRight(), top + firstChild.getHeight());
}
}
}
}

View File

@@ -61,7 +61,7 @@ abstract class BaseActivity<T : ViewBinding>(val inflater: (inflater: LayoutInfl
private var mLoadingDialog: QMUITipDialog? = null
//默认删除去掉titleTopBar底部间隔下划线
var mDeleteBottomDivider: Boolean = true
private var mDeleteBottomDivider: Boolean = true
//Activity是否在前台显示运行
var isFrontRunning = false
@@ -86,8 +86,8 @@ abstract class BaseActivity<T : ViewBinding>(val inflater: (inflater: LayoutInfl
// 监听因输入框弹出,遮挡输入框,界面移动,需要移动的view
private var mTranslateView: View? = null
/*****************************监听软键盘弹出,输入框上移start************************************/
private var isKeyboardTranslate = true
/*****************************监听软键盘弹出,输入框上移 ************************************/
var isKeyboardTranslate = true
//是否需要适配底部EdgeToEdge
var isEdgeToEdgeAdapterNavigationBars = true
@@ -168,6 +168,7 @@ abstract class BaseActivity<T : ViewBinding>(val inflater: (inflater: LayoutInfl
override fun onPause() {
super.onPause()
isFrontRunning = false
//键盘隐藏恢复默认状态
mTranslateView?.apply {
scrollTo(0, 0)
@@ -231,16 +232,25 @@ abstract class BaseActivity<T : ViewBinding>(val inflater: (inflater: LayoutInfl
/**
* 监听键盘弹出和隐藏,解决键盘弹出挡住输入框的问题
*/
fun setListenKeyboardChange(windowTranslateY: Int = 500, view: View = window.decorView) {
fun setListenKeyboardChange(
windowTranslateY: Int = 500,
view: View = window.decorView,
methodType: Int = ConstantInt.Type0
) {
val metrics = getResources().displayMetrics
val screenWidth = metrics.widthPixels
// val screenHeight = metrics.heightPixels
val scaleFactor = screenWidth / 1080 // 假设 1080 是设计宽度
window.decorView.viewTreeObserver.addOnGlobalLayoutListener {
onLayoutChange(view, windowTranslateY * scaleFactor)
view.viewTreeObserver.addOnGlobalLayoutListener {
if (methodType == ConstantInt.Type0) {
onLayoutChange(view, windowTranslateY * scaleFactor)
} else {
onGlobalLayoutChange(view, windowTranslateY * scaleFactor)
}
}
}
/**
* 设置其他包含的view点击。隐藏软键盘如ScrollView
*/
@@ -560,16 +570,24 @@ abstract class BaseActivity<T : ViewBinding>(val inflater: (inflater: LayoutInfl
val exceptionMessage = it.exceptionOrNull()?.message
//服务器返回错误code
val exceptionCode: String? = it.exceptionOrNull()?.toString()
LogUtil.d("Throwable", "code=${exceptionCode},${exceptionMessage}")
LogUtil.d("Throwable异常", "code=${exceptionCode},${exceptionMessage}")
if (null != exceptionCode) {
//处理注册用户已存在的情况
if (exceptionCode == ErrorCode.USER_HAS_EXIST.toString()) {
getResultCallback.onRequestError(exceptionCode)
}
if (exceptionCode == ErrorCode.DEVICE_HAS_BIND.toString()) {
val str =
String.format(getString(R.string.txt_device_has_bind), exceptionMessage)
showToast(str)
getResultCallback.onInterceptCode()
return
}
//拦截请求异常code
if (netErrorCodeTips(exceptionCode, isShowCodeError)) {
else if (netErrorCodeTips(exceptionCode, isShowCodeError)) {
//已经处理相关错误码就直接返回
getResultCallback.onErrorCode()
getResultCallback.onInterceptCode()
return
}
}
@@ -675,10 +693,10 @@ abstract class BaseActivity<T : ViewBinding>(val inflater: (inflater: LayoutInfl
return true
}
//该设备已被绑定
ErrorCode.DEVICE_HAS_BIND.toString() -> {
if (isShowCodeError) showToast(R.string.txt_device_has_bind)
return true
}
// ErrorCode.DEVICE_HAS_BIND.toString() -> {
// if (isShowCodeError) showToast(R.string.txt_device_has_bind)
// return true
// }
//设备不存在
ErrorCode.DEVICE_NOT_EXIST.toString() -> {
if (isShowCodeError) showToast(R.string.txt_no_dfu)
@@ -834,10 +852,10 @@ abstract class BaseActivity<T : ViewBinding>(val inflater: (inflater: LayoutInfl
private fun onLayoutChange(translateView: View, translateY: Int) {
mTranslateView = translateView
//获取当前屏幕内容的高度
val screenHeight = window.decorView.height
val screenHeight = translateView.height
//获取View可见区域的bottom
val rect = Rect()
window.decorView.getWindowVisibleDisplayFrame(rect)
translateView.getWindowVisibleDisplayFrame(rect)
if (screenHeight - getNavigatorBarHeight() > rect.bottom) {
// 获取按钮的左上角按钮高度为40dp
// val location = IntArray(2)
@@ -845,7 +863,7 @@ abstract class BaseActivity<T : ViewBinding>(val inflater: (inflater: LayoutInfl
// val bottom = location[1] + resources.getDimensionPixelSize(R.dimen.dp_80)
//// 如果按钮被覆盖,移动整个界面向上移动
// if (bottom > rect.bottom) {
// window.decorView.scrollBy(0, bottom - rect.bottom)
// translateView.scrollBy(0, bottom - rect.bottom)
// isKeyboardTranslate = true
// }
if (!isKeyboardTranslate) {
@@ -864,5 +882,28 @@ abstract class BaseActivity<T : ViewBinding>(val inflater: (inflater: LayoutInfl
hideSoftKeyboardCallback()
}
}
private fun onGlobalLayoutChange(translateView: View, translateY: Int) {
mTranslateView = translateView
val r = Rect()
translateView.getWindowVisibleDisplayFrame(r)
val heightDiff = translateView.getRootView().height - (r.bottom - r.top)
if (heightDiff > 200) { // 如果高度差大于200说明键盘是弹出的
// 进行布局调整
if (!isKeyboardTranslate) {
//移动到指定位置点坐标
translateView.scrollBy(0, translateY)
isKeyboardTranslate = true
}
LogUtil.e("如果高度差大于200说明键盘是弹出的")
showSoftKeyboardCallback()
} else {
// 键盘隐藏,恢复布局
isKeyboardTranslate = false
LogUtil.e("键盘隐藏,恢复布局")
translateView.scrollTo(0, 0)
hideSoftKeyboardCallback()
}
}
/*****************************监听软键盘弹出输入框上移end************************************/
}

View File

@@ -57,6 +57,11 @@ abstract class BaseDialog<T : ViewBinding>
initView()
}
override fun onStart() {
super.onStart()
// ✅ 每次显示都会执行刷新数据、更新UI等
}
abstract fun initView()
/**

View File

@@ -11,6 +11,7 @@ import android.view.ViewGroup
import androidx.activity.result.ActivityResultLauncher
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewbinding.ViewBinding
import com.abbidot.baselibrary.util.LogUtil
import com.abbidot.tracker.R
@@ -71,6 +72,14 @@ abstract class BaseFragment<T : ViewBinding>(
*/
open fun liveDataObserve() {}
/**
* 获取当前activity
*/
protected fun <T : FragmentActivity> getHostActivity(clazz: Class<T>): T? {
val act = activity ?: return null
return if (clazz.isInstance(act)) clazz.cast(act) else null
}
/**
* 初始化
*/

View File

@@ -9,12 +9,16 @@ import kotlinx.parcelize.Parcelize
* @description:设备详情
*/
@Parcelize
data class DeviceDetailBean(var deviceOutId: String,
var deviceId: String,
var macId: String,
var pet: PetBean?,
var fenceCount: Int,
var surplusDays: Int,
var familieCount: Int,var deviceInfo:DeviceInfoBean?) : Parcelable {
constructor() : this("", "", "", null, 0, 0,0,null)
data class DeviceDetailBean(
var deviceOutId: String,
var deviceId: String,
var macId: String,
var email: String,
var pet: PetBean?,
var fenceCount: Int,
var surplusDays: Int,
var familieCount: Int,
var deviceInfo: DeviceInfoBean?
) : Parcelable {
constructor() : this("", "", "", "", null, 0, 0, 0, null)
}

View File

@@ -36,6 +36,8 @@ data class MapDeviceBean(
var startTime: String,
var endTime: String,
var deviceType: Int,
var wifiZoneName: String,
var version: String,
var notifyLocationFail: Boolean,
var canShowBattery: Boolean,//是否可以显示电池提示布局
var isCloseBattery: Boolean,//是否关闭电池提示
@@ -72,6 +74,8 @@ data class MapDeviceBean(
"",
"",
1,
"",
"",
false,
false,
false,

View File

@@ -24,5 +24,9 @@ data class PackageBean(
var planTimeMonthsCount: Int,
var everyMonthSafeFee: Double,
var billedMode: String,
var selected: Boolean
var selected: Boolean,
var bottomBgColor: String,
var listTitleCode: Int,
var planNameCode: Int,
var list: MutableList<PackageBenefitsBean>?
) : Parcelable

View File

@@ -1,8 +1,12 @@
package com.abbidot.tracker.bean
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
/**
*Created by .yzq on 2024/9/5/005.
* @link
* @description:
*/
data class PackageBenefitsBean(var title: String, var status: Int, var titleCode: Int)
@Parcelize
data class PackageBenefitsBean(var title: String, var status: Int, var titleCode: Int) : Parcelable

View File

@@ -18,8 +18,9 @@ data class PayResultBean(
var expirationTime: String,
var deviceOutId: String,
var deviceId: String,
var deviceType: Int,
//设备充值类型0=首次设备充值激活1=已添加设备再次添加设备充值2=给当前的设备续费或者升级套餐
var rechargeType: Int
) : Parcelable {
constructor() : this("", "", "", 0L, "", "", "", ConstantInt.Type1)
constructor() : this("", "", "", 0L, "", "", "", 1, ConstantInt.Type1)
}

View File

@@ -0,0 +1,3 @@
package com.abbidot.tracker.bean
data class PaymentIDBean(var stripeMethodInfo: CreditCardBean, var paypalMethodInfo: UserBean)

View File

@@ -32,13 +32,18 @@ data class PetBean(
var macID: String,
var mealType: Int,
var deviceType: Int,
var serviceVersion: String,//服务器上最新固件版本号
var showDFUDialog: Boolean,//是否显示了固件升级弹窗
var showNoWifiDialog: Boolean,//是否显示了没有设置wifi弹窗
var availableOrder: Int,//判断套餐是否可用或过期1是可用 0不可用
var latitude: Double,
var longitude: Double,
var deviceId: String
) : Parcelable, BaseDiffBean() {
constructor() : this(
"", "", "", "", 0, 1, MMKVUtil.getString(MMKVKey.UserId), "", 0, Utils.formatTime(
System.currentTimeMillis(), Utils.DATE_FORMAT_PATTERN_CN
), "", 0f, 0f, "", "", "", 1, 1, 1, ""
), "", 0f, 0f, "", "", "", 1, 1, "", false, false, 1, 0.0, 0.0, ""
)
override fun isSameObject(other: Any): Boolean {

View File

@@ -55,6 +55,8 @@ data class SubscriptionsOrderBean(
var endTime: Long,
var refundTime: Long,
var planTimeMonthsCount: Int,
var isRefundable: Int,//是否显示退款按钮 1:是 0:否
var isAutoRenewal: Int,//是否是自动续订 1:是 0:否
@MultipleEntity var menuType: Int,
var isUpdateOrder: Int = 0//是否是升级订单 1:是 0:否
) : Parcelable, MultiItemEntity {
@@ -101,6 +103,8 @@ data class SubscriptionsOrderBean(
0L,
0L,
0,
0,
0,
menuType,
0
)
@@ -148,6 +152,8 @@ data class SubscriptionsOrderBean(
0L,
0L,
0,
0,
0,
MultipleEntity.TEXT,
0
)

View File

@@ -49,6 +49,8 @@ import androidx.annotation.IntDef
ConstantInt.BasicPackage,
ConstantInt.PremiumPackage,
ConstantInt.MinSportGoal,
ConstantInt.PetSpecialType,
ConstantInt.DefaultType,
ConstantInt.NoShare,
ConstantInt.ReportTimeOutTime,
ConstantInt.PetLocationType
@@ -100,6 +102,8 @@ annotation class ConstantInt {
const val OtherLocationType = 2
const val UserLocationType = 1
const val PetLocationType = 0
const val PetSpecialType = 3
const val DefaultType = 4
//默认的运动目标时间(min)
const val DefaultSportGoal = 60

View File

@@ -55,6 +55,7 @@ import androidx.annotation.StringDef
ConstantString.Upgrade,
ConstantString.Password,
ConstantString.PackageUnitDay,
ConstantString.Lists,
ConstantString.PackageUnitMonth,
ConstantString.PackageUnitYear,
ConstantString.SetMealIndex
@@ -95,6 +96,7 @@ annotation class ConstantString {
const val Latitude = "latitude"
const val Longitude = "longitude"
const val isFirstBind = "isFirstBind"
const val Lists = "list"
const val isCheck = "isCheck"
const val Amount = "amount"

View File

@@ -10,5 +10,6 @@ interface GetResultCallback {
//默认可以不重写相当于java中的default修饰的
fun onRequestError(exceptionCode: String?) {}
fun onErrorCode() {}
//已拦截的code
fun onInterceptCode() {}
}

View File

@@ -0,0 +1,10 @@
package com.abbidot.tracker.constant
/**
*Created by .yzq on 2026/4/8/周三.
* @link
* @description:
*/
interface LinkMapCallback {
fun onCameraListener(type:Int)
}

View File

@@ -72,7 +72,7 @@ class LoginRegisterCNActivity :
fun switchFragment(index: Int) {
setTopTitle(getString(R.string.login_txt_welcome))
setTopContent(getString(R.string.login_txt_seeyou))
setTopContent(getString(R.string.app_name))
supportFragmentManager.commit {

View File

@@ -104,7 +104,7 @@ class HomeMapNavigationActivity :
// val mGoogleApiClient = mGoogleSignInClient.asGoogleApiClient()
ViewUtil.instance.imageLoadUrl(
ViewUtil.instance.imageLoadUrl(mContext,
mViewBinding.homeMapNavigationPetHead.appHeadImage, pet!!.imgurl
)
if (TextUtils.isEmpty(historyDataBean!!.address)) {

View File

@@ -140,7 +140,7 @@ class MapLiveActivity : BaseActivity<ActivityMapLiveBinding>(ActivityMapLiveBind
mViewBinding.apply {
mapLivePetLayout.mapPetName.text = historyDataBean.petName
ViewUtil.instance.imageLoadUrl(
ViewUtil.instance.imageLoadUrl(mContext,
mapLivePetLayout.mapPetHead.appHeadImage, historyDataBean.petImgurl
)
val batteryString =

View File

@@ -490,6 +490,10 @@ class FencesAddActivity : BaseActivity<ActivityFencesAddBinding>(ActivityFencesA
override fun rectStartDragClick() {
}
override fun rectMinSizeClick() {
}
override fun rectEndDragClick() {
}
@@ -504,6 +508,9 @@ class FencesAddActivity : BaseActivity<ActivityFencesAddBinding>(ActivityFencesA
}
override fun circleMinSizeClick() {
}
override fun circleEndDragClick() {
}

View File

@@ -89,7 +89,7 @@ class RechargeDeviceDetailCNActivity : BaseActivity<ActivityRechargeDeviceDetail
} else {
itemCardPetHead.appHeadImage.let {
it.visibility = View.VISIBLE
ViewUtil.instance.imageLoadUrl(it, rechargeDeviceBean.pet!!.imgurl)
ViewUtil.instance.imageLoadUrl(mContext,it, rechargeDeviceBean.pet!!.imgurl)
}
itemCardPetName.let {
it.visibility = View.VISIBLE

View File

@@ -78,7 +78,7 @@ class RechargeOrderDetailCNActivity : BaseActivity<ActivityRechargeOrderDetailCn
it.text = getString(R.string.txt_select_payment_method)
it.detailTextView.visibility = View.VISIBLE
it.detailTextView.background =
ContextCompat.getDrawable(mContext!!, R.drawable.pic_wechatpay)
ContextCompat.getDrawable(mContext, R.drawable.pic_wechatpay)
setOnClickListenerViews(startPayMoneyBtnCn, it)
}
@@ -87,7 +87,7 @@ class RechargeOrderDetailCNActivity : BaseActivity<ActivityRechargeOrderDetailCn
//底部弹出菜单
val languageList = mutableListOf(R.drawable.pic_wechatpay, R.drawable.pic_alipay)
val bottomListSheetBuilder =
ViewUtil.instance.showBottomSheetList(mContext!!, { dialog, _, position, _ ->
ViewUtil.instance.showBottomSheetList(mContext, { dialog, _, position, _ ->
dialog.dismiss()
mPayWay = position
mViewBinding.rechargeOrderDetailCnPayWay.detailTextView.background =
@@ -190,7 +190,11 @@ class RechargeOrderDetailCNActivity : BaseActivity<ActivityRechargeOrderDetailCn
it.itemCardPetHead.appHeadImage.visibility = View.VISIBLE
it.itemCardPetName.visibility = View.VISIBLE
it.itemCardPetName.text = pet!!.petName
ViewUtil.instance.imageLoadUrl(it.itemCardPetHead.appHeadImage, pet!!.imgurl)
ViewUtil.instance.imageLoadUrl(
mContext,
it.itemCardPetHead.appHeadImage,
pet!!.imgurl
)
}
}
}
@@ -201,7 +205,7 @@ class RechargeOrderDetailCNActivity : BaseActivity<ActivityRechargeOrderDetailCn
val str = getString(R.string.txt_month_until) + "\t$accountFee"
mViewBinding.tvNeedPayMoneyCn.text = str
mViewBinding.rechargeOrderDetailCnAmount.let {
if (hotType == ConstantInt.Type1) {
if (hotType == ConstantInt.Type1) {
it.rechargeAmountNormalHotImage.visibility = View.VISIBLE
} else {
it.rechargeAmountNormalHotImage.visibility = View.GONE
@@ -210,11 +214,7 @@ class RechargeOrderDetailCNActivity : BaseActivity<ActivityRechargeOrderDetailCn
it.txtRechargeAmountName.text = name
val perMonth = if (period > 1) {
String.format(getString(R.string.pet_managet_age), period)
} else {
String.format(getString(R.string.pet_managet_age_1), period)
}
val perMonth = ""
it.rechargeAmountTwoTime.text = perMonth
// val subscriptionPlan =

View File

@@ -9,6 +9,7 @@ import com.abbidot.tracker.util.Util
import com.baidu.mapapi.search.route.BikingRouteResult
import com.baidu.mapapi.search.route.DrivingRouteResult
import com.baidu.mapapi.search.route.IndoorRouteResult
import com.baidu.mapapi.search.route.IntegralRouteResult
import com.baidu.mapapi.search.route.MassTransitRouteResult
import com.baidu.mapapi.search.route.OnGetRoutePlanResultListener
import com.baidu.mapapi.search.route.PlanNode
@@ -144,6 +145,10 @@ class RoutePlanningViewModel : ViewModel() {
override fun onGetBikingRouteResult(p0: BikingRouteResult?) {
}
override fun onGetIntegralRouteResult(p0: IntegralRouteResult?) {
}
})
}

View File

@@ -17,16 +17,17 @@ class DFUNewDialog(context: Context) :
private var mVersion = ""
override fun initView() {
setCanceledOnTouchOutside(false)
// setCanceledOnTouchOutside(false)
setCancelable(false)
mViewBinding.apply {
btnDialogDfuNewUpgradeNow.setChangeAlphaWhenPress(true)
setOnClickListenerViews(tvDialogDfuNewLaterBtn, btnDialogDfuNewDone)
}
}
fun startDfuState(version: String, onClick: () -> Unit) {
mVersion = version
val ver = String.format(mContext.getString(R.string.txt_new_firmware_version), mVersion)
fun startDfuState(version: String, autoDfu: Boolean, onClick: () -> Unit) {
mVersion = "\t$version"
val ver = String.format(mContext.getString(R.string.txt_about_version), mVersion)
mViewBinding.apply {
rlDialogDfuNewAfterLayout.visibility = View.GONE
llDialogDfuNewBeforeLayout.visibility = View.VISIBLE
@@ -36,7 +37,11 @@ class DFUNewDialog(context: Context) :
inDFUState()
onClick()
}
0 }
}
if (autoDfu) {
inDFUState()
onClick()
}
}
private fun inDFUState() {

View File

@@ -1,9 +1,12 @@
package com.abbidot.tracker.dialog
import android.content.Context
import android.view.View
import android.widget.CompoundButton
import com.abbidot.baselibrary.constant.MMKVKey
import com.abbidot.baselibrary.list.BaseRecyclerAdapter
import com.abbidot.baselibrary.util.AppUtils
import com.abbidot.baselibrary.util.MMKVUtil
import com.abbidot.tracker.base.BaseDialog
import com.abbidot.tracker.bean.DataBean
import com.abbidot.tracker.databinding.DialogSelectMapTypeLayoutBinding
@@ -18,12 +21,16 @@ import com.abbidot.tracker.util.ViewUtil
class SelectMapTypeDialog(
context: Context,
adapter: BaseRecyclerAdapter<*>,
checkedChangeListener: CompoundButton.OnCheckedChangeListener? = null
fenceCheckedListener: CompoundButton.OnCheckedChangeListener? = null,
dashedCheckedListener: CompoundButton.OnCheckedChangeListener? = null,
showAllPetCheckedListener: CompoundButton.OnCheckedChangeListener? = null
) : BaseDialog<DialogSelectMapTypeLayoutBinding>(
DialogSelectMapTypeLayoutBinding::inflate, context
) {
private var mAdapter = adapter
private val mCheckedChangeListener = checkedChangeListener
private val mFenceCheckedListener = fenceCheckedListener
private val mDashedCheckedListener = dashedCheckedListener
private val mShowAllPetCheckedListener = showAllPetCheckedListener
override fun initView() {
mViewBinding.apply {
@@ -31,10 +38,15 @@ class SelectMapTypeDialog(
context, rvShowMapTypeList, mAdapter, right = AppUtils.dpToPx(58)
)
cbDialogMapFencesSwitch.isChecked = Util.getShowFenceSp()
cbDialogMapFencesSwitch.setOnCheckedChangeListener(mCheckedChangeListener)
cbDialogMapDashedLineSwitch.isChecked = MMKVUtil.getBoolean(MMKVKey.ShowDashedLine)
cbDialogMapAllPetSwitch.isChecked = MMKVUtil.getBoolean(MMKVKey.ShowAllPet)
cbDialogMapFencesSwitch.setOnCheckedChangeListener(mFenceCheckedListener)
cbDialogMapDashedLineSwitch.setOnCheckedChangeListener(mDashedCheckedListener)
cbDialogMapAllPetSwitch.setOnCheckedChangeListener(mShowAllPetCheckedListener)
}
}
/**
* 检测地图类型有没有改变
*/
@@ -58,4 +70,16 @@ class SelectMapTypeDialog(
fun setFencesSwitch(checked: Boolean) {
mViewBinding.cbDialogMapFencesSwitch.isChecked = checked
}
fun setDashedSwitch(checked: Boolean) {
mViewBinding.cbDialogMapDashedLineSwitch.isChecked = checked
}
fun setShowAllPetSwitch(checked: Boolean) {
mViewBinding.cbDialogMapAllPetSwitch.isChecked = checked
}
fun showAllPetSwitch(isShow: Boolean) {
mViewBinding.llMapTypeShowAllPetSwitch.visibility = if (isShow) View.VISIBLE else View.GONE
}
}

View File

@@ -21,15 +21,17 @@ import java.util.Calendar
* @link
* @description:显示日历弹窗
* @param canSelectFutureDate 平时正常日期true不能选择未来时间
* @param minLastDayRange 最小天数能选最近多少天0表示没有限制
*/
class ShowCalenderAndTimeDialog(
context: Context,
showCalenderTextView: TextView,
okListener: OnDialogOkListener? = null,
okListener: OnDialogSelectListener? = null,
format: String = Utils.DATE_FORMAT_PATTERN_EN1,
canSelectFutureDate: Boolean = false,
calenderShowTimestamp: Long = 0,
minYear: Int = 2023
minYear: Int = 2023,
minLastDayRange: Int = 0
) : BaseDialog<DialogCalenderAndTimeLayoutBinding>(
DialogCalenderAndTimeLayoutBinding::inflate, context
), OnValueChangeListener {
@@ -44,7 +46,8 @@ class ShowCalenderAndTimeDialog(
private val mOkListener = okListener
private val mMinYear = minYear
private val mCalenderShowTimestamp = calenderShowTimestamp
private var mCalenderShowTimestamp = calenderShowTimestamp
private val mMinLastDayRange = minLastDayRange
override fun initView() {
mMonths = context.resources.getStringArray(R.array.array_month)
@@ -58,7 +61,23 @@ class ShowCalenderAndTimeDialog(
val cYear = calendar.get(Calendar.YEAR)
val month = calendar.get(Calendar.MONTH) + 1
val day = calendar.get(Calendar.DAY_OF_MONTH)
it.setRange(mMinYear, 1, 1, cYear, month, day)
if (mMinLastDayRange > 0) {
val minTimestamp = Utils.getBeforeHowTimestamp(
calendar.timeInMillis, mMinLastDayRange.toLong()
)
val minDate =
Utils.formatTime(minTimestamp, Utils.DATE_FORMAT_PATTERN_CN).split("-")
it.setRange(
minDate[0].toInt(),
minDate[1].toInt(),
minDate[2].toInt(),
cYear,
month,
day
)
} else {
it.setRange(mMinYear, 1, 1, cYear, month, day)
}
}
updateMonthYear()
@@ -86,7 +105,7 @@ class ShowCalenderAndTimeDialog(
0,
23,
5,
24,
16,
NumberPickerValueFill0Format(),
this@ShowCalenderAndTimeDialog
)
@@ -98,14 +117,12 @@ class ShowCalenderAndTimeDialog(
0,
59,
5,
24,
16,
NumberPickerValueFill0Format(),
this@ShowCalenderAndTimeDialog
)
}
//根据传入的时间戳进行还原显示
setSelectDate(mCalenderShowTimestamp)
setOnClickListenerViews(
llDialogCalenderLayout.ivSelectCalendarMonthLeft,
@@ -117,6 +134,12 @@ class ShowCalenderAndTimeDialog(
}
}
override fun onStart() {
super.onStart()
//根据传入的时间戳进行还原显示
setSelectDate(mCalenderShowTimestamp)
}
/**
* 根据传入的时间戳进行还原显示
* @param showTimestamp 13位时间戳
@@ -172,16 +195,18 @@ class ShowCalenderAndTimeDialog(
}:${Utils.fill2Digits(npDialogCalenderMin.value)}:00"
val timesTamp = Utils.stringToTimestamp(selectMonthYear)
val nowTimestamp = System.currentTimeMillis()
if (timesTamp > nowTimestamp) {
//时间戳还原
setSelectDate(nowTimestamp)
mCalenderShowTimestamp = nowTimestamp
mShowCalenderTextView.text = Utils.formatTime(nowTimestamp, mDateFormat)
mOkListener?.onSelectClick(this@ShowCalenderAndTimeDialog, nowTimestamp)
} else {
mCalenderShowTimestamp = timesTamp
mShowCalenderTextView.text = Utils.stringToDate(
selectMonthYear, Utils.DATE_FORMAT_PATTERN_CN2, mDateFormat
)
mOkListener?.onSelectClick(this@ShowCalenderAndTimeDialog, timesTamp)
}
mOkListener?.onOkClick(this@ShowCalenderAndTimeDialog)
dismiss()
}
}

View File

@@ -100,7 +100,7 @@ class ShowCalenderDialog(
* 根据传入的时间戳进行还原显示
* @param showTimestamp 13位时间戳
*/
fun setSelectDate(showTimestamp: Long) {
private fun setSelectDate(showTimestamp: Long) {
if (showTimestamp > 0) {
val calendar = java.util.Calendar.getInstance().apply {
timeInMillis = showTimestamp

View File

@@ -23,6 +23,7 @@ import com.abbidot.tracker.bean.OrderBean
import com.abbidot.tracker.bean.PackageBean
import com.abbidot.tracker.bean.PackageTypeBean
import com.abbidot.tracker.bean.PayResultBean
import com.abbidot.tracker.bean.PaymentIDBean
import com.abbidot.tracker.bean.PetAllInfoBean
import com.abbidot.tracker.bean.PetBean
import com.abbidot.tracker.bean.RechargeDeviceBean
@@ -47,8 +48,6 @@ import retrofit2.http.Query
interface INetworkService {
companion object {
//宠物勋章图片url
const val BASE_PET_BADGE_URL = "http://162.62.53.38:9998/static/TrackerBadgeImages/"
private const val IP_SERVER = "https://aws.abbidot.com"
// private const val IP_SERVER = "https://192.168.0.22"
// const val BASE_URL = "http://ec2-50-18-65-40.us-west-1.compute.amazonaws.com:8090/abbidot/"
@@ -837,6 +836,16 @@ interface INetworkService {
@Query("toTime") toTime: Long
): BaseResponse<MutableList<HistoryDataBean>>
/**
* 获取设备进出围栏历史数据
*/
@GET("data/getHistoryInOutFenceList")
suspend fun getHistoryFenceList(
@Query("deviceId") deviceId: String,
@Query("beginTimeStamp") fromTime: Long,
@Query("endTimeStamp") toTime: Long
): BaseResponse<MutableList<MessageBean>>
/**
* 设置运动目标
*/
@@ -1131,119 +1140,12 @@ interface INetworkService {
suspend fun rsaDecodeTest(
@Field("encryptedData") encryptedData: String
): BaseResponse<String>
/*******************************************以下是国内版本接口***********************************/
/**
* 获取微信登录的OpedId
*/
// @Headers("${CommonRequestInterceptor.HEADERS_NAME}:${CommonRequestInterceptor.HEADERS_value}")
// @GET("oauth2/access_token")
// suspend fun getWXOpedId(@Query("appid") appid: String,
// @Query("secret") secret: String,
// @Query("code") code: String,
// @Query("grant_type") grant_type: String): BaseResponse<String>
/**
* 微信登录
* 获取Stripe、paypal支付id
*/
@GET("user/wxLogin")
suspend fun wxLogin(@Query("code") code: String): BaseResponse<UserBean>
/**
* 微信绑定
*/
@FormUrlEncoded
@POST("user/weixinBind")
suspend fun wxBind(
@Field("phone") phone: String,
@Field("verificationCode") verificationCode: String,
@Field("wxId") wxId: String
): BaseResponse<UserBean>
/**
* 发送验证码
*/
@GET("user/sendCode")
suspend fun sendCode(
@Query("phone") phone: String,
//发送类型 1是验证码登录 2微信绑定 3注册 4忘记密码
@Query("type") type: Int
): BaseResponse<String>
/**
* 验证码登录
*/
@FormUrlEncoded
@POST("user/phoneLogin")
suspend fun phoneLogin(
@Field("phone") phone: String, @Field("verificationCode") verificationCode: String
): BaseResponse<UserBean>
/**
* 手机号验证码验证
*/
@FormUrlEncoded
@POST("user/validateCode")
suspend fun validatePhoneCode(
@Field("phone") phone: String, @Field("code") code: String,
//验证码类型 1是注册 2是忘记密码
@Field("type") type: Int
): BaseResponse<String>
/**
* 账号密码登录
*/
@FormUrlEncoded
@POST("user/accountPasswordLogin")
suspend fun accountPasswordLogin(
@Field("phone") phone: String, @Field("password") password: String
): BaseResponse<UserBean>
/**
* 用户注册
*/
@FormUrlEncoded
@POST("user/register")
suspend fun register(
@Field("phone") phone: String, @Field("password") password: String
): BaseResponse<String>
/**
* 重置密码
*/
@FormUrlEncoded
@POST("user/resetPassword")
suspend fun resetNewPassword(
@Field("phone") phone: String, @Field("password") password: String
): BaseResponse<String>
/**
* 获取微信支付Prepay_id
*/
@FormUrlEncoded
@POST("order/getWxPayOrder")
suspend fun getWxPayOrder(
@Field("feePackage") feePackage: String,
@Field("deviceId") deviceId: String,
@Field("payFee") payFee: Double,
@Field("period") period: Float,
@Field("userId") userId: String,
@Field("username") username: String
): BaseResponse<WXPayOrderBean>
/**
* 获取支付宝支付订单
*/
@FormUrlEncoded
@POST("order/getAlipayOrder")
suspend fun getAlipayOrder(
@Field("feePackage") feePackage: String,
@Field("deviceId") deviceId: String,
@Field("payFee") payFee: Double,
@Field("period") period: Float,
@Field("userId") userId: String,
@Field("username") username: String
): BaseResponse<AlipayOrderBean>
@GET("user/getUserPaymentMethodID")
suspend fun getUserPaymentMethodID(@Query("userId") userId: String): BaseResponse<PaymentIDBean>
/**
* 获取订阅订单列表
@@ -1275,13 +1177,21 @@ interface INetworkService {
@Query("userId") userId: String, @Query("deviceId") deviceId: String
): BaseResponse<MutableList<SubscriptionsOrderBean>>
/**
* 获取设备充值得的历史记录(包括自动续订)
*/
@GET("order$SUBSCRIPTIONS_V3/subscriptions/historyIncludRenew")
suspend fun getHistoryIncludeRenew(
@Query("subscriptionId") subscriptionId: String
): BaseResponse<MutableList<SubscriptionsOrderBean>>
/**
* 提交退款申请
*/
@FormUrlEncoded
@POST("order$SUBSCRIPTIONS_V3/refund/commit")
suspend fun commitRefund(
@Field("currency_code") currency_code: String,
@Field("currency_code") currencyCode: String,
@Field("orderNum") orderNum: String,
@Field("chargeId") chargeId: String,
@Field("amount") amount: Int,
@@ -1446,4 +1356,119 @@ interface INetworkService {
@FormUrlEncoded
@POST("map/setupRefreshLocation")
suspend fun setupRefreshLocation(@Field("deviceId") deviceId: String): BaseResponse<String>
/*******************************************以下是国内版本接口***********************************/
/**
* 获取微信登录的OpedId
*/
// @Headers("${CommonRequestInterceptor.HEADERS_NAME}:${CommonRequestInterceptor.HEADERS_value}")
// @GET("oauth2/access_token")
// suspend fun getWXOpedId(@Query("appid") appid: String,
// @Query("secret") secret: String,
// @Query("code") code: String,
// @Query("grant_type") grant_type: String): BaseResponse<String>
/**
* 微信登录
*/
@GET("user/wxLogin")
suspend fun wxLogin(@Query("code") code: String): BaseResponse<UserBean>
/**
* 微信绑定
*/
@FormUrlEncoded
@POST("user/weixinBind")
suspend fun wxBind(
@Field("phone") phone: String,
@Field("verificationCode") verificationCode: String,
@Field("wxId") wxId: String
): BaseResponse<UserBean>
/**
* 发送验证码
*/
@GET("user/sendCode")
suspend fun sendCode(
@Query("phone") phone: String,
//发送类型 1是验证码登录 2微信绑定 3注册 4忘记密码
@Query("type") type: Int
): BaseResponse<String>
/**
* 验证码登录
*/
@FormUrlEncoded
@POST("user/phoneLogin")
suspend fun phoneLogin(
@Field("phone") phone: String, @Field("verificationCode") verificationCode: String
): BaseResponse<UserBean>
/**
* 手机号验证码验证
*/
@FormUrlEncoded
@POST("user/validateCode")
suspend fun validatePhoneCode(
@Field("phone") phone: String, @Field("code") code: String,
//验证码类型 1是注册 2是忘记密码
@Field("type") type: Int
): BaseResponse<String>
/**
* 账号密码登录
*/
@FormUrlEncoded
@POST("user/accountPasswordLogin")
suspend fun accountPasswordLogin(
@Field("phone") phone: String, @Field("password") password: String
): BaseResponse<UserBean>
/**
* 用户注册
*/
@FormUrlEncoded
@POST("user/register")
suspend fun register(
@Field("phone") phone: String, @Field("password") password: String
): BaseResponse<String>
/**
* 重置密码
*/
@FormUrlEncoded
@POST("user/resetPassword")
suspend fun resetNewPassword(
@Field("phone") phone: String, @Field("password") password: String
): BaseResponse<String>
/**
* 获取微信支付Prepay_id
*/
@FormUrlEncoded
@POST("order/getWxPayOrder")
suspend fun getWxPayOrder(
@Field("feePackage") feePackage: String,
@Field("deviceId") deviceId: String,
@Field("payFee") payFee: Double,
@Field("period") period: Float,
@Field("userId") userId: String,
@Field("username") username: String
): BaseResponse<WXPayOrderBean>
/**
* 获取支付宝支付订单
*/
@FormUrlEncoded
@POST("order/getAlipayOrder")
suspend fun getAlipayOrder(
@Field("feePackage") feePackage: String,
@Field("deviceId") deviceId: String,
@Field("payFee") payFee: Double,
@Field("period") period: Float,
@Field("userId") userId: String,
@Field("username") username: String
): BaseResponse<AlipayOrderBean>
/*******************************************以上是国内版本接口end***********************************/
}

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