修改icon,完善注销逻辑,增加点击MessageListItem复制文本功能
@ -13,6 +13,8 @@
|
||||
<option value="$PROJECT_DIR$/app" />
|
||||
<option value="$PROJECT_DIR$/common" />
|
||||
<option value="$PROJECT_DIR$/compose" />
|
||||
<option value="$PROJECT_DIR$/pushdeerclient" />
|
||||
<option value="$PROJECT_DIR$/pushdeercommon" />
|
||||
</set>
|
||||
</option>
|
||||
<option name="resolveModulePerSourceSet" value="false" />
|
||||
|
@ -14,8 +14,13 @@
|
||||
<entry key="../../../../layout/compose-model-1641659962289.xml" value="2.0" />
|
||||
<entry key="../../../../layout/compose-model-1641694023752.xml" value="0.1" />
|
||||
<entry key="../../../../layout/compose-model-1642733328920.xml" value="2.0" />
|
||||
<entry key="../../../../layout/compose-model-1642826587452.xml" value="2.0" />
|
||||
<entry key="app/src/main/res/drawable/fragment_qr_scan.xml" value="0.12314814814814815" />
|
||||
<entry key="app/src/main/res/drawable/ic_markdown.xml" value="0.12962962962962962" />
|
||||
<entry key="app/src/main/res/layout/activity_qr_scan.xml" value="0.1" />
|
||||
<entry key="app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml" value="0.1" />
|
||||
<entry key="common/src/main/res/layout/activity_qr_scan.xml" value="0.1" />
|
||||
<entry key="pushdeerclient/src/main/res/drawable-v24/ic_markdown.xml" value="0.11944444444444445" />
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
|
@ -1,32 +1,34 @@
|
||||
# PushDeer for Android
|
||||
|
||||
|
||||
|
||||
### 适配进度
|
||||
|
||||
* MiPush(状态:已调通、已接入)
|
||||
* miui 12.5.6 正常
|
||||
* 原生、类原生 可成功注册,无法收到推送,可能和地区识别有关,待解决
|
||||
* miui下处于"几乎可用"的状态,已接入 appleId
|
||||
* miui √
|
||||
* Mokee √
|
||||
* HuaWei √
|
||||
* 部分原生、类原生 可成功注册,无法收到推送,可能和地区识别有关,待解决
|
||||
|
||||
### TODO
|
||||
|
||||
* ~~调通 MiPush~~
|
||||
* ~~接入 MiPush~~
|
||||
* 完善 log ~~采集~~ 回传机制,便于调试
|
||||
* 测试不同厂商设备上的通知推送效果
|
||||
* 测试不同厂商设备/系统上的通知推送效果 miui√ Mokee√ HuaWei√
|
||||
* ~~接入 PushDeer~~
|
||||
* ~~界面设计:BottomBar+Navigation(Device Key Message Setting)~~
|
||||
* 调整 KeyList MessageList 等处的自定义绘制
|
||||
* ~~增加 DeviceList 外的侧滑手势~~
|
||||
* ~~增加侧滑手势相关动作~~
|
||||
* 增加各种操作前的二次确认弹窗,包括自动登陆
|
||||
* 增加非Miui设备的权限获取
|
||||
* 增加手动修改服务器地址/退出登陆的逻辑(并放置到登陆界面)
|
||||
* 增加手动修改服务器地址逻辑(并放置到登陆界面)
|
||||
* ~~增加退出登陆的逻辑~~
|
||||
* 增加登陆过程中的图形提示
|
||||
* 增加对PushKey重命名的逻辑
|
||||
* 增加对设备重命名的逻辑
|
||||
* 增加长按复制消息内容的逻辑
|
||||
* ~~增加对PushKey重命名的逻辑~~
|
||||
* ~~增加对设备重命名的逻辑~~
|
||||
* ~~增加长按复制消息内容的逻辑~~
|
||||
* 增加点击设置界面用户名修改用户名逻辑
|
||||
* ~~适配image类型的消息显示~~
|
||||
* ~~修改app图标~~
|
||||
|
||||
|
||||
### 日志
|
||||
|
||||
@ -105,6 +107,12 @@
|
||||
* 修改登陆界面ui
|
||||
* 增加key/device的重命名逻辑
|
||||
* 适配英语和中文
|
||||
* 增加点击PushKey显示二维码功能
|
||||
|
||||
* 2022-01-22
|
||||
* 增加点击 Message 列表项目复制文本功能
|
||||
* 增加适配Image类型Message的显示
|
||||
* 完善登陆注销逻辑
|
||||
|
||||
|
||||
### 感谢
|
||||
|
@ -91,11 +91,12 @@ dependencies {
|
||||
implementation "androidx.room:room-runtime:$room_version"
|
||||
kapt "androidx.room:room-compiler:$room_version"
|
||||
|
||||
// qr
|
||||
implementation 'com.google.zxing:core:3.2.1'
|
||||
implementation 'cn.bingoogolapple:bga-qrcodecore:1.1.7@aar'
|
||||
implementation 'cn.bingoogolapple:bga-zxing:1.1.7@aar'
|
||||
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.2'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
|
||||
|
||||
final def markwon_version = '4.6.2'
|
||||
implementation "io.noties.markwon:core:$markwon_version"
|
||||
|
@ -4,12 +4,13 @@
|
||||
package="com.pushdeer.os">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
tools:ignore="ScopedStorage" />
|
||||
<!-- <uses-permission android:name="android.permission.READ_PHONE_STATE" />-->
|
||||
<!-- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"-->
|
||||
<!-- tools:ignore="ScopedStorage" />-->
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
|
||||
@ -18,8 +19,9 @@
|
||||
android:protectionLevel="signature" />
|
||||
<uses-permission android:name="com.pushdeer.os.permission.MIPUSH_RECEIVE" />
|
||||
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
|
||||
<!-- for QR -->
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-feature android:name="android.hardware.camera.autofocus" />
|
||||
<uses-feature android:name="android.hardware.camera" />
|
||||
|
||||
@ -49,11 +51,11 @@
|
||||
|
||||
<activity
|
||||
android:screenOrientation="portrait"
|
||||
android:name=".activity.QrScanActivity"
|
||||
android:name="com.wh.common.activity.QrScanActivity"
|
||||
android:theme="@style/Theme.PushDeer.NoActionBar"
|
||||
/>
|
||||
|
||||
<!-- start -->
|
||||
<!-- miPush components start -->
|
||||
|
||||
<service
|
||||
android:name="com.xiaomi.push.service.XMPushService"
|
||||
@ -86,7 +88,7 @@
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<!-- end -->
|
||||
<!-- miPush components end -->
|
||||
|
||||
<receiver
|
||||
android:name="com.xiaomi.push.service.receivers.PingReceiver"
|
||||
@ -101,7 +103,6 @@
|
||||
<receiver
|
||||
android:name="com.pushdeer.os.receiver.MessageReceiver"
|
||||
android:exported="true">
|
||||
<!--这里com.xiaomi.mipushdemo.DemoMessageRreceiver改成app中定义的完整类名-->
|
||||
<intent-filter>
|
||||
<action android:name="com.xiaomi.mipush.RECEIVE_MESSAGE" />
|
||||
</intent-filter>
|
||||
|
BIN
android/app/src/main/ic_launcher-playstore.png
Normal file
After Width: | Height: | Size: 31 KiB |
@ -5,11 +5,8 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.text.util.Linkify
|
||||
import android.widget.Toast
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.animation.ExperimentalAnimationApi
|
||||
@ -29,7 +26,6 @@ import coil.ImageLoader
|
||||
import com.google.accompanist.insets.ProvideWindowInsets
|
||||
import com.google.accompanist.insets.statusBarsPadding
|
||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||
import com.pushdeer.os.activity.QrScanActivity
|
||||
import com.pushdeer.os.holder.RequestHolder
|
||||
import com.pushdeer.os.store.SettingStore
|
||||
import com.pushdeer.os.ui.compose.componment.MyAlertDialog
|
||||
@ -37,12 +33,12 @@ import com.pushdeer.os.ui.compose.page.LogDogPage
|
||||
import com.pushdeer.os.ui.compose.page.LoginPage
|
||||
import com.pushdeer.os.ui.compose.page.main.MainPage
|
||||
import com.pushdeer.os.ui.theme.PushDeerTheme
|
||||
import com.pushdeer.os.util.ActivityOpener
|
||||
import com.pushdeer.os.util.SystemUtil
|
||||
import com.pushdeer.os.viewmodel.LogDogViewModel
|
||||
import com.pushdeer.os.viewmodel.MessageViewModel
|
||||
import com.pushdeer.os.viewmodel.PushDeerViewModel
|
||||
import com.pushdeer.os.viewmodel.UiViewModel
|
||||
import com.wh.common.util.UiUtils
|
||||
import io.noties.markwon.Markwon
|
||||
import io.noties.markwon.image.coil.CoilImagesPlugin
|
||||
import io.noties.markwon.linkify.LinkifyPlugin
|
||||
@ -62,18 +58,36 @@ class MainActivity : AppCompatActivity(), RequestHolder {
|
||||
override val messageViewModel: MessageViewModel by viewModels { viewModelFactory }
|
||||
override val settingStore: SettingStore by lazy { (application as App).storeKeeper.settingStore }
|
||||
override val fragmentManager: FragmentManager by lazy { this.supportFragmentManager }
|
||||
// override val resource: Resources by lazy { this.resource }
|
||||
|
||||
override val coilImageLoader: ImageLoader by lazy {
|
||||
ImageLoader.Builder(this)
|
||||
.apply {
|
||||
availableMemoryPercentage(0.5)
|
||||
bitmapPoolPercentage(0.5)
|
||||
crossfade(true)
|
||||
crossfade(750)
|
||||
allowHardware(true)
|
||||
}
|
||||
.build()
|
||||
}
|
||||
override val alert: RequestHolder.AlertRequest by lazy { object : RequestHolder.AlertRequest(resources) {} }
|
||||
override val alert: RequestHolder.AlertRequest by lazy {
|
||||
object : RequestHolder.AlertRequest(resources) {}
|
||||
}
|
||||
override val key: RequestHolder.KeyRequest by lazy {
|
||||
object : RequestHolder.KeyRequest(this) {}
|
||||
}
|
||||
override val device: RequestHolder.DeviceRequest by lazy {
|
||||
object : RequestHolder.DeviceRequest(this) {}
|
||||
}
|
||||
override val message: RequestHolder.MessageRequest by lazy {
|
||||
object : RequestHolder.MessageRequest(this) {}
|
||||
}
|
||||
override val clip: RequestHolder.ClipRequest by lazy {
|
||||
object : RequestHolder.ClipRequest(
|
||||
getSystemService(
|
||||
Context.CLIPBOARD_SERVICE
|
||||
) as ClipboardManager
|
||||
) {}
|
||||
}
|
||||
|
||||
override val markdown: Markwon by lazy {
|
||||
Markwon.builder(this)
|
||||
@ -84,10 +98,9 @@ class MainActivity : AppCompatActivity(), RequestHolder {
|
||||
|
||||
override lateinit var globalNavController: NavHostController
|
||||
override lateinit var coroutineScope: CoroutineScope
|
||||
override lateinit var myActivity: ComponentActivity
|
||||
override val clipboardManager by lazy { getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager }
|
||||
|
||||
override lateinit var activityOpener: ActivityResultLauncher<Intent>
|
||||
override lateinit var myActivity: AppCompatActivity
|
||||
override lateinit var qrScanActivityOpener: ActivityResultLauncher<Intent>
|
||||
override lateinit var requestPermissionOpener: ActivityResultLauncher<Array<String>>
|
||||
|
||||
@ExperimentalAnimationApi
|
||||
@ExperimentalMaterialApi
|
||||
@ -95,28 +108,23 @@ class MainActivity : AppCompatActivity(), RequestHolder {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
myActivity = this
|
||||
activityOpener =
|
||||
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
Toast.makeText(
|
||||
this,
|
||||
"${result.data?.getStringExtra(QrScanActivity.DataKey)}",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
qrScanActivityOpener = ActivityOpener.forResult(this)
|
||||
requestPermissionOpener = ActivityOpener.forPermission(this)
|
||||
|
||||
UiUtils.keepScreenOn(window)
|
||||
setContent {
|
||||
globalNavController = rememberNavController()
|
||||
coroutineScope = rememberCoroutineScope()
|
||||
val useDarkIcons = MaterialTheme.colors.isLight
|
||||
val systemUiController = rememberSystemUiController()
|
||||
when {
|
||||
SystemUtil.isMiui() -> systemUiController.setStatusBarColor(Color.Transparent, useDarkIcons)
|
||||
SystemUtil.isMiui() -> systemUiController.setStatusBarColor(
|
||||
Color.Transparent,
|
||||
useDarkIcons
|
||||
)
|
||||
else -> systemUiController.setSystemBarsColor(Color.Transparent, useDarkIcons)
|
||||
}
|
||||
WindowCompat.setDecorFitsSystemWindows(window, true)
|
||||
miPushRepository.regId.observe(this) {
|
||||
// 这个操作放到注册成功后进行
|
||||
settingStore.thisDeviceId = it
|
||||
}
|
||||
|
||||
|
@ -1,66 +1,66 @@
|
||||
package com.pushdeer.os.activity
|
||||
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import cn.bingoogolapple.qrcode.core.QRCodeView
|
||||
import com.pushdeer.os.R
|
||||
|
||||
|
||||
class QrScanActivity : AppCompatActivity(), QRCodeView.Delegate {
|
||||
|
||||
private val TAG = "WH_" + javaClass.simpleName
|
||||
private lateinit var qrCode: QRCodeView
|
||||
|
||||
companion object {
|
||||
val RequestCode_get_scan_result = 436
|
||||
val DataKey = "qr_scan_result"
|
||||
|
||||
fun forScanResultIntent(context: Context): Intent {
|
||||
return Intent(context, QrScanActivity::class.java).apply {
|
||||
putExtra(DataKey, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_qr_scan)
|
||||
qrCode = findViewById(R.id.qrcode1)
|
||||
qrCode.setDelegate(this)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
Log.d(TAG, "onStart")
|
||||
qrCode.startSpotAndShowRect()
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
Log.d(TAG, "onStop")
|
||||
qrCode.stopCamera()
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
qrCode.onDestroy()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun onScanQRCodeSuccess(result: String?) {
|
||||
Log.d(TAG, "onScanQRCodeSuccess: $result")
|
||||
qrCode.stopCamera()
|
||||
val intent = Intent()
|
||||
intent.putExtra(DataKey, result)
|
||||
setResult(RequestCode_get_scan_result, intent)
|
||||
finish()
|
||||
}
|
||||
|
||||
override fun onScanQRCodeOpenCameraError() {
|
||||
Log.e(TAG, "onScanQRCodeOpenCameraError")
|
||||
qrCode.startSpotAndShowRect()
|
||||
}
|
||||
}
|
||||
//package com.pushdeer.os.activity
|
||||
//
|
||||
//
|
||||
//import android.content.Context
|
||||
//import android.content.Intent
|
||||
//import android.os.Bundle
|
||||
//import android.util.Log
|
||||
//import androidx.appcompat.app.AppCompatActivity
|
||||
//import cn.bingoogolapple.qrcode.core.QRCodeView
|
||||
//import com.pushdeer.os.R
|
||||
//
|
||||
//
|
||||
//class QrScanActivity : AppCompatActivity(), QRCodeView.Delegate {
|
||||
//
|
||||
// private val TAG = "WH_" + javaClass.simpleName
|
||||
// private lateinit var qrCode: QRCodeView
|
||||
//
|
||||
// companion object {
|
||||
// val RequestCode_get_scan_result = 436
|
||||
// val DataKey = "qr_scan_result"
|
||||
//
|
||||
// fun forScanResultIntent(context: Context): Intent {
|
||||
// return Intent(context, QrScanActivity::class.java).apply {
|
||||
// putExtra(DataKey, 1)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// override fun onCreate(savedInstanceState: Bundle?) {
|
||||
// super.onCreate(savedInstanceState)
|
||||
// setContentView(R.layout.activity_qr_scan)
|
||||
// qrCode = findViewById(R.id.qrcode1)
|
||||
// qrCode.setDelegate(this)
|
||||
// }
|
||||
//
|
||||
// override fun onStart() {
|
||||
// super.onStart()
|
||||
// Log.d(TAG, "onStart")
|
||||
// qrCode.startSpotAndShowRect()
|
||||
// }
|
||||
//
|
||||
// override fun onStop() {
|
||||
// Log.d(TAG, "onStop")
|
||||
// qrCode.stopCamera()
|
||||
// super.onStop()
|
||||
// }
|
||||
//
|
||||
// override fun onDestroy() {
|
||||
// qrCode.onDestroy()
|
||||
// super.onDestroy()
|
||||
// }
|
||||
//
|
||||
// override fun onScanQRCodeSuccess(result: String?) {
|
||||
// Log.d(TAG, "onScanQRCodeSuccess: $result")
|
||||
// qrCode.stopCamera()
|
||||
// val intent = Intent()
|
||||
// intent.putExtra(DataKey, result)
|
||||
// setResult(RequestCode_get_scan_result, intent)
|
||||
// finish()
|
||||
// }
|
||||
//
|
||||
// override fun onScanQRCodeOpenCameraError() {
|
||||
// Log.e(TAG, "onScanQRCodeOpenCameraError")
|
||||
// qrCode.startSpotAndShowRect()
|
||||
// }
|
||||
//}
|
@ -4,9 +4,9 @@ import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Intent
|
||||
import android.content.res.Resources
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
@ -15,7 +15,6 @@ import androidx.fragment.app.FragmentManager
|
||||
import androidx.navigation.NavHostController
|
||||
import coil.ImageLoader
|
||||
import com.pushdeer.os.R
|
||||
import com.pushdeer.os.activity.QrScanActivity
|
||||
import com.pushdeer.os.data.api.data.request.DeviceInfo
|
||||
import com.pushdeer.os.data.api.data.response.Message
|
||||
import com.pushdeer.os.data.api.data.response.PushKey
|
||||
@ -24,6 +23,7 @@ import com.pushdeer.os.viewmodel.LogDogViewModel
|
||||
import com.pushdeer.os.viewmodel.MessageViewModel
|
||||
import com.pushdeer.os.viewmodel.PushDeerViewModel
|
||||
import com.pushdeer.os.viewmodel.UiViewModel
|
||||
import com.wh.common.activity.QrScanActivity
|
||||
import io.noties.markwon.Markwon
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
@ -37,106 +37,22 @@ interface RequestHolder {
|
||||
val settingStore: SettingStore
|
||||
val globalNavController: NavHostController
|
||||
val coroutineScope: CoroutineScope
|
||||
val myActivity: ComponentActivity
|
||||
val myActivity: AppCompatActivity
|
||||
val markdown: Markwon
|
||||
val activityOpener: ActivityResultLauncher<Intent>
|
||||
val qrScanActivityOpener: ActivityResultLauncher<Intent>
|
||||
val requestPermissionOpener:ActivityResultLauncher<Array<String>>
|
||||
val coilImageLoader: ImageLoader
|
||||
|
||||
// val resource:Resources
|
||||
|
||||
val fragmentManager: FragmentManager
|
||||
|
||||
val alert: AlertRequest
|
||||
|
||||
val clipboardManager: ClipboardManager
|
||||
|
||||
fun copyPlainString(str: String) {
|
||||
clipboardManager.setPrimaryClip(ClipData.newPlainText("pushdeer-pushkey", str))
|
||||
}
|
||||
val key:KeyRequest
|
||||
val device:DeviceRequest
|
||||
val message:MessageRequest
|
||||
val clip:ClipRequest
|
||||
|
||||
fun startQrScanActivity() {
|
||||
activityOpener.launch(QrScanActivity.forScanResultIntent(myActivity))
|
||||
}
|
||||
|
||||
fun keyGen() {
|
||||
coroutineScope.launch {
|
||||
pushDeerViewModel.keyGen()
|
||||
}
|
||||
}
|
||||
|
||||
fun keyRegen(keyId: String) {
|
||||
coroutineScope.launch {
|
||||
pushDeerViewModel.keyRegen(keyId)
|
||||
}
|
||||
}
|
||||
|
||||
fun keyRemove(pushKey: PushKey) {
|
||||
coroutineScope.launch {
|
||||
pushDeerViewModel.keyList.remove(pushKey)
|
||||
pushDeerViewModel.keyRemove(pushKey.id)
|
||||
}
|
||||
}
|
||||
|
||||
fun keyRename(pushKey: PushKey){
|
||||
coroutineScope.launch {
|
||||
pushDeerViewModel.keyRename(pushKey){
|
||||
coroutineScope.launch {
|
||||
pushDeerViewModel.keyList()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun deviceReg(deviceInfo: DeviceInfo) {
|
||||
coroutineScope.launch {
|
||||
pushDeerViewModel.deviceReg(deviceInfo)
|
||||
}
|
||||
}
|
||||
|
||||
fun deviceRemove(deviceInfo: DeviceInfo) {
|
||||
coroutineScope.launch {
|
||||
pushDeerViewModel.deviceList.remove(deviceInfo)
|
||||
pushDeerViewModel.deviceRemove(deviceInfo.id)
|
||||
}
|
||||
}
|
||||
|
||||
fun deviceRename(deviceInfo: DeviceInfo) {
|
||||
coroutineScope.launch {
|
||||
pushDeerViewModel.deviceRename(deviceInfo) {
|
||||
coroutineScope.launch {
|
||||
pushDeerViewModel.deviceList()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun messagePush(text: String, desp: String, type: String, pushkey: String) {
|
||||
coroutineScope.launch {
|
||||
pushDeerViewModel.messagePush(text, desp, type, pushkey)
|
||||
}
|
||||
}
|
||||
|
||||
fun messagePushTest(text: String) {
|
||||
if (pushDeerViewModel.keyList.isNotEmpty()) {
|
||||
messagePush(text, "pushtest", "markdown", pushDeerViewModel.keyList[0].key)
|
||||
coroutineScope.launch {
|
||||
delay(1000)
|
||||
pushDeerViewModel.messageList()
|
||||
}
|
||||
} else {
|
||||
alert.alert(
|
||||
R.string.global_alert_title_alert,
|
||||
R.string.main_message_send_alert,
|
||||
onOk = {})
|
||||
}
|
||||
}
|
||||
|
||||
fun messageRemove(message: Message, onDone: () -> Unit = {}) {
|
||||
coroutineScope.launch {
|
||||
// pushDeerViewModel.messageList.remove(message)
|
||||
pushDeerViewModel.messageRemove(message.id)
|
||||
onDone()
|
||||
}
|
||||
qrScanActivityOpener.launch(QrScanActivity.forScanResultIntent(myActivity))
|
||||
}
|
||||
|
||||
fun toggleMessageSender() {
|
||||
@ -145,9 +61,21 @@ interface RequestHolder {
|
||||
}
|
||||
|
||||
fun clearLogDog() {
|
||||
alert.alert(R.string.global_alert_title_confirm,"Clear?",onOk = {
|
||||
coroutineScope.launch {
|
||||
logDogViewModel.clear()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
abstract class ClipRequest(private val clipboardManager: ClipboardManager) {
|
||||
fun copyMessagePlainText(str: String) {
|
||||
clipboardManager.setPrimaryClip(ClipData.newPlainText("pushdeer-copy-plain-text", str))
|
||||
}
|
||||
|
||||
fun copyPushKey(str: String){
|
||||
clipboardManager.setPrimaryClip(ClipData.newPlainText("pushdeer-copy-pushkey", str))
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AlertRequest(private val resources: Resources) {
|
||||
@ -192,5 +120,101 @@ interface RequestHolder {
|
||||
) {
|
||||
alert(resources.getString(title), content, onOk, onCancel)
|
||||
}
|
||||
|
||||
fun alert(
|
||||
@StringRes title: Int,
|
||||
content: String,
|
||||
onOk: () -> Unit,
|
||||
onCancel: () -> Unit = {}
|
||||
) {
|
||||
alert(resources.getString(title), content, onOk, onCancel)
|
||||
}
|
||||
}
|
||||
|
||||
abstract class KeyRequest(private val requestHolder: RequestHolder){
|
||||
fun gen() {
|
||||
requestHolder.coroutineScope.launch {
|
||||
requestHolder.pushDeerViewModel.keyGen()
|
||||
}
|
||||
}
|
||||
|
||||
fun regen(keyId: String) {
|
||||
requestHolder.coroutineScope.launch {
|
||||
requestHolder.pushDeerViewModel.keyRegen(keyId)
|
||||
}
|
||||
}
|
||||
|
||||
fun remove(pushKey: PushKey) {
|
||||
requestHolder.coroutineScope.launch {
|
||||
requestHolder.pushDeerViewModel.keyList.remove(pushKey)
|
||||
requestHolder.pushDeerViewModel.keyRemove(pushKey.id)
|
||||
}
|
||||
}
|
||||
|
||||
fun rename(pushKey: PushKey) {
|
||||
requestHolder.coroutineScope.launch {
|
||||
requestHolder.pushDeerViewModel.keyRename(pushKey) {
|
||||
requestHolder.coroutineScope.launch {
|
||||
requestHolder.pushDeerViewModel.keyList()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class DeviceRequest(private val requestHolder: RequestHolder){
|
||||
fun deviceReg(deviceInfo: DeviceInfo) {
|
||||
requestHolder.coroutineScope.launch {
|
||||
requestHolder.pushDeerViewModel.deviceReg(deviceInfo)
|
||||
}
|
||||
}
|
||||
|
||||
fun deviceRemove(deviceInfo: DeviceInfo) {
|
||||
requestHolder.coroutineScope.launch {
|
||||
requestHolder.pushDeerViewModel.deviceList.remove(deviceInfo)
|
||||
requestHolder.pushDeerViewModel.deviceRemove(deviceInfo.id)
|
||||
}
|
||||
}
|
||||
|
||||
fun deviceRename(deviceInfo: DeviceInfo) {
|
||||
requestHolder.coroutineScope.launch {
|
||||
requestHolder.pushDeerViewModel.deviceRename(deviceInfo) {
|
||||
requestHolder.coroutineScope.launch {
|
||||
requestHolder.pushDeerViewModel.deviceList()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class MessageRequest(private val requestHolder: RequestHolder){
|
||||
fun messagePush(text: String, desp: String, type: String, pushkey: String) {
|
||||
requestHolder.coroutineScope.launch {
|
||||
requestHolder.pushDeerViewModel.messagePush(text, desp, type, pushkey)
|
||||
}
|
||||
}
|
||||
|
||||
fun messagePushTest(text: String) {
|
||||
if (requestHolder.pushDeerViewModel.keyList.isNotEmpty()) {
|
||||
messagePush(text, "pushtest", "markdown", requestHolder.pushDeerViewModel.keyList[0].key)
|
||||
requestHolder.coroutineScope.launch {
|
||||
delay(1000)
|
||||
requestHolder.pushDeerViewModel.messageList()
|
||||
}
|
||||
} else {
|
||||
requestHolder.alert.alert(
|
||||
R.string.global_alert_title_alert,
|
||||
R.string.main_message_send_alert,
|
||||
onOk = {})
|
||||
}
|
||||
}
|
||||
|
||||
fun messageRemove(message: Message, onDone: () -> Unit = {}) {
|
||||
requestHolder.coroutineScope.launch {
|
||||
// pushDeerViewModel.messageList.remove(message)
|
||||
requestHolder.pushDeerViewModel.messageRemove(message.id)
|
||||
onDone()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -108,7 +108,7 @@ fun CardItemMultiLine(
|
||||
|
||||
@ExperimentalMaterialApi
|
||||
@Composable
|
||||
fun CardItemWithContent(onClick: () -> Unit = {}, content: @Composable () -> Unit = {}) {
|
||||
fun CardItemWithContent(onClick: () -> Unit, content: @Composable () -> Unit = {}) {
|
||||
Card(
|
||||
onClick = onClick,
|
||||
shape = RoundedCornerShape(4.dp),
|
||||
@ -123,6 +123,22 @@ fun CardItemWithContent(onClick: () -> Unit = {}, content: @Composable () -> Uni
|
||||
)
|
||||
}
|
||||
|
||||
@ExperimentalMaterialApi
|
||||
@Composable
|
||||
fun CardItemWithContent(content: @Composable () -> Unit = {}) {
|
||||
Card(
|
||||
shape = RoundedCornerShape(4.dp),
|
||||
modifier = Modifier
|
||||
.border(
|
||||
width = 1.dp,
|
||||
color = MainBlue,
|
||||
shape = RoundedCornerShape(4.dp)
|
||||
),
|
||||
content = content,
|
||||
elevation = 5.dp
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ListBottomBlankItem() {
|
||||
Row(
|
||||
|
@ -1,8 +1,10 @@
|
||||
package com.pushdeer.os.ui.compose.componment
|
||||
|
||||
import android.widget.ImageView
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.*
|
||||
@ -17,10 +19,12 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import com.pushdeer.os.R
|
||||
import com.pushdeer.os.data.api.data.response.PushKey
|
||||
import com.pushdeer.os.holder.RequestHolder
|
||||
import com.pushdeer.os.ui.theme.MBlue
|
||||
import com.wh.common.util.QRCodeGenerator
|
||||
import com.wh.common.util.TimeUtils
|
||||
|
||||
@ExperimentalMaterialApi
|
||||
@ -52,7 +56,7 @@ fun KeyItem(key: PushKey,requestHolder: RequestHolder) {
|
||||
},
|
||||
onOk = {
|
||||
key.name = name
|
||||
requestHolder.keyRename(key)
|
||||
requestHolder.key.rename(key)
|
||||
}
|
||||
)
|
||||
}) {
|
||||
@ -118,24 +122,36 @@ fun KeyItem(key: PushKey,requestHolder: RequestHolder) {
|
||||
color = Color.Gray,
|
||||
shape = RoundedCornerShape(4.dp)
|
||||
)
|
||||
.clickable {
|
||||
requestHolder.alert.alert("QrCode For ${key.name}", {
|
||||
Box(
|
||||
modifier = Modifier.width(400.dp)
|
||||
) {
|
||||
AndroidView(
|
||||
factory = {
|
||||
ImageView(it).apply {
|
||||
this.setImageBitmap(
|
||||
QRCodeGenerator(
|
||||
key.key,
|
||||
400.dp.value.toInt(),
|
||||
400.dp.value.toInt()
|
||||
).qrCode
|
||||
)
|
||||
}
|
||||
},
|
||||
modifier = Modifier.align(alignment = Alignment.Center)
|
||||
)
|
||||
}
|
||||
}, onOk = {})
|
||||
}
|
||||
.padding(horizontal = 14.dp, vertical = 8.dp)
|
||||
)
|
||||
// Canvas(modifier = Modifier
|
||||
// .fillMaxWidth()
|
||||
// .height(16.dp), onDraw = {
|
||||
// val linePath = Path()
|
||||
// val linePaint = Paint()
|
||||
// linePaint.pathEffect = PathEffect.dashPathEffect(FloatArray(10),10F)
|
||||
// drawIntoCanvas {
|
||||
// it.drawPath(linePath, linePaint)
|
||||
// }
|
||||
// })
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
OutlinedButton(
|
||||
onClick = { requestHolder.keyRegen(key.id) },
|
||||
onClick = { requestHolder.key.regen(key.id) },
|
||||
colors = ButtonDefaults.outlinedButtonColors(
|
||||
backgroundColor = Color.Transparent,
|
||||
contentColor = MaterialTheme.colors.MBlue
|
||||
@ -147,7 +163,7 @@ fun KeyItem(key: PushKey,requestHolder: RequestHolder) {
|
||||
}
|
||||
Button(
|
||||
onClick = {
|
||||
requestHolder.copyPlainString(key.key)
|
||||
requestHolder.clip.copyPushKey(key.key)
|
||||
},
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
backgroundColor = MaterialTheme.colors.MBlue,
|
||||
|
@ -1,7 +1,9 @@
|
||||
package com.pushdeer.os.ui.compose.componment
|
||||
|
||||
import android.widget.ImageView
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Card
|
||||
@ -12,12 +14,12 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import coil.load
|
||||
import com.pushdeer.os.R
|
||||
import com.pushdeer.os.data.database.entity.MessageEntity
|
||||
import com.pushdeer.os.holder.RequestHolder
|
||||
@ -27,11 +29,14 @@ import com.pushdeer.os.values.ConstValues
|
||||
|
||||
@ExperimentalMaterialApi
|
||||
@Composable
|
||||
fun PlainTextMessageItem(message: MessageEntity) {
|
||||
fun PlainTextMessageItem(message: MessageEntity,requestHolder: RequestHolder) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(4.dp))
|
||||
.clickable {
|
||||
requestHolder.clip.copyMessagePlainText(message.text)
|
||||
}
|
||||
.background(color = MaterialTheme.colors.surface)
|
||||
) {
|
||||
|
||||
@ -47,7 +52,7 @@ fun PlainTextMessageItem(message: MessageEntity) {
|
||||
modifier = Modifier.size(40.dp)
|
||||
)
|
||||
Text(
|
||||
text = "${message.text}·${
|
||||
text = "${message.pushkey_name}·${
|
||||
CurrentTimeUtil.resolveUTCTimeAndNow(
|
||||
message.created_at,
|
||||
System.currentTimeMillis()
|
||||
@ -56,9 +61,9 @@ fun PlainTextMessageItem(message: MessageEntity) {
|
||||
)
|
||||
}
|
||||
|
||||
CardItemWithContent() {
|
||||
CardItemWithContent {
|
||||
Text(
|
||||
text = message.desp,
|
||||
text = message.text,
|
||||
overflow = TextOverflow.Visible,
|
||||
lineHeight = 24.sp,
|
||||
modifier = Modifier
|
||||
@ -71,11 +76,14 @@ fun PlainTextMessageItem(message: MessageEntity) {
|
||||
|
||||
@ExperimentalMaterialApi
|
||||
@Composable
|
||||
fun ImageMessageItem(message: MessageEntity) {
|
||||
fun ImageMessageItem(message: MessageEntity, requestHolder: RequestHolder) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(4.dp))
|
||||
.clickable {
|
||||
requestHolder.clip.copyMessagePlainText(message.text)
|
||||
}
|
||||
.background(color = MaterialTheme.colors.surface)
|
||||
) {
|
||||
|
||||
@ -92,7 +100,7 @@ fun ImageMessageItem(message: MessageEntity) {
|
||||
modifier = Modifier.size(40.dp)
|
||||
)
|
||||
Text(
|
||||
text = "${message.text}·${
|
||||
text = "${message.pushkey_name}·${
|
||||
CurrentTimeUtil.resolveUTCTimeAndNow(
|
||||
message.created_at,
|
||||
System.currentTimeMillis()
|
||||
@ -100,12 +108,13 @@ fun ImageMessageItem(message: MessageEntity) {
|
||||
}"
|
||||
)
|
||||
}
|
||||
Card(modifier = Modifier.fillMaxWidth(), onClick = {}) {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.logo_com_x2),
|
||||
contentDescription = "",
|
||||
contentScale = ContentScale.FillWidth
|
||||
)
|
||||
Card(modifier = Modifier.fillMaxWidth()) {
|
||||
AndroidView(factory = {
|
||||
ImageView(it).apply {
|
||||
scaleType = ImageView.ScaleType.FIT_CENTER
|
||||
load(message.text, requestHolder.coilImageLoader)
|
||||
}
|
||||
}, modifier = Modifier.fillMaxWidth())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -117,6 +126,9 @@ fun MarkdownMessageItem(message: MessageEntity, requestHolder: RequestHolder) {
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(4.dp))
|
||||
.clickable {
|
||||
requestHolder.clip.copyMessagePlainText(message.text)
|
||||
}
|
||||
.background(color = MaterialTheme.colors.surface)
|
||||
) {
|
||||
|
||||
@ -163,6 +175,13 @@ fun MarkdownMessageItem(message: MessageEntity, requestHolder: RequestHolder) {
|
||||
|
||||
}, modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
// .pointerInput(Unit) {
|
||||
// this.detectTapGestures(
|
||||
// onLongPress = {
|
||||
// Log.d("WH_", "MarkdownMessageItem: ")
|
||||
// }
|
||||
// )
|
||||
// }
|
||||
.padding(16.dp)
|
||||
)
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ fun LoginPage(requestHolder: RequestHolder) {
|
||||
}
|
||||
}
|
||||
is SignInWithAppleResult.Failure -> {
|
||||
requestHolder.alert.alert("Warning", {
|
||||
requestHolder.alert.alert("Warning Apple Id Login Failed", {
|
||||
result.error.message
|
||||
}, onOk = {})
|
||||
Log.d(
|
||||
|
@ -1,6 +1,5 @@
|
||||
package com.pushdeer.os.ui.compose.page.main
|
||||
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
@ -41,7 +40,7 @@ fun DeviceListPage(requestHolder: RequestHolder) {
|
||||
onOk = {})
|
||||
// device regid got failed
|
||||
} else {
|
||||
requestHolder.deviceReg(
|
||||
requestHolder.device.deviceReg(
|
||||
deviceInfo = DeviceInfo().apply {
|
||||
name = SystemUtil.getDeviceModel()
|
||||
device_id = requestHolder.settingStore.thisDeviceId
|
||||
@ -72,7 +71,7 @@ fun DeviceListPage(requestHolder: RequestHolder) {
|
||||
mutableStateOf(deviceInfo.name)
|
||||
}
|
||||
SwipeToDismissItem(
|
||||
onAction = { requestHolder.deviceRemove(deviceInfo) }
|
||||
onAction = { requestHolder.device.deviceRemove(deviceInfo) }
|
||||
) {
|
||||
CardItemSingleLineWithIcon(
|
||||
onClick = {
|
||||
@ -99,7 +98,7 @@ fun DeviceListPage(requestHolder: RequestHolder) {
|
||||
},
|
||||
onOk = {
|
||||
deviceInfo.name = name
|
||||
requestHolder.deviceRename(deviceInfo)
|
||||
requestHolder.device.deviceRename(deviceInfo)
|
||||
}
|
||||
)
|
||||
},
|
||||
@ -110,7 +109,7 @@ fun DeviceListPage(requestHolder: RequestHolder) {
|
||||
)
|
||||
}) " else deviceInfo.name
|
||||
)
|
||||
Log.d("WH_", "DeviceListPage: $deviceInfo")
|
||||
// Log.d("WH_", "DeviceListPage: $deviceInfo")
|
||||
}
|
||||
}
|
||||
item {
|
||||
|
@ -25,7 +25,7 @@ import com.pushdeer.os.ui.navigation.Page
|
||||
fun KeyListPage(requestHolder: RequestHolder) {
|
||||
MainPageFrame(
|
||||
titleStringId = Page.Keys.labelStringId,
|
||||
onSideIconClick = { requestHolder.keyGen() }
|
||||
onSideIconClick = { requestHolder.key.gen() }
|
||||
) {
|
||||
if(requestHolder.pushDeerViewModel.keyList.isEmpty()){
|
||||
Column(
|
||||
@ -42,7 +42,7 @@ fun KeyListPage(requestHolder: RequestHolder) {
|
||||
items(
|
||||
requestHolder.pushDeerViewModel.keyList,
|
||||
key = { item: PushKey -> item.id }) { pushKey: PushKey ->
|
||||
SwipeToDismissItem(onAction = { requestHolder.keyRemove(pushKey) }
|
||||
SwipeToDismissItem(onAction = { requestHolder.key.remove(pushKey) }
|
||||
) {
|
||||
KeyItem(key = pushKey, requestHolder = requestHolder)
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ fun MainPage(requestHolder: RequestHolder) {
|
||||
}
|
||||
|
||||
var titleStringId by remember {
|
||||
mutableStateOf(Page.Devices.labelStringId)
|
||||
mutableStateOf(Page.Messages.labelStringId)
|
||||
}
|
||||
val navController = rememberNavController()
|
||||
Scaffold(
|
||||
@ -98,7 +98,7 @@ fun MainPage(requestHolder: RequestHolder) {
|
||||
)
|
||||
NavHost(
|
||||
navController = navController,
|
||||
startDestination = Page.Devices.route,
|
||||
startDestination = Page.Messages.route,
|
||||
) {
|
||||
composable(Page.Devices.route) {
|
||||
DeviceListPage(requestHolder = requestHolder)
|
||||
|
@ -73,7 +73,7 @@ fun MessageListPage(requestHolder: RequestHolder) {
|
||||
)
|
||||
Button(
|
||||
onClick = {
|
||||
requestHolder.messagePushTest(s)
|
||||
requestHolder.message.messagePushTest(s)
|
||||
},
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
backgroundColor = MaterialTheme.colors.MBlue,
|
||||
@ -90,7 +90,7 @@ fun MessageListPage(requestHolder: RequestHolder) {
|
||||
key = { item: MessageEntity -> item.id }) { message: MessageEntity ->
|
||||
SwipeToDismissItem(
|
||||
onAction = {
|
||||
requestHolder.messageRemove(message.toMessage(), onDone = {
|
||||
requestHolder.message.messageRemove(message.toMessage(), onDone = {
|
||||
requestHolder.messageViewModel.delete(message)
|
||||
})
|
||||
},
|
||||
@ -98,8 +98,8 @@ fun MessageListPage(requestHolder: RequestHolder) {
|
||||
) {
|
||||
when (message.type) {
|
||||
"markdown" -> MarkdownMessageItem(message, requestHolder)
|
||||
"text" -> PlainTextMessageItem(message)
|
||||
"image" -> ImageMessageItem(message)
|
||||
"text" -> PlainTextMessageItem(message, requestHolder)
|
||||
"image" -> ImageMessageItem(message, requestHolder)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,10 +26,18 @@ fun SettingPage(requestHolder: RequestHolder) {
|
||||
text = "${stringResource(id = R.string.main_setting_user_hi)} ${requestHolder.pushDeerViewModel.userInfo.name} !",
|
||||
buttonString = stringResource(id = R.string.main_setting_user_logout)
|
||||
) {
|
||||
requestHolder.pushDeerViewModel.deviceList.filter { it.device_id == requestHolder.settingStore.thisDeviceId }.forEach {
|
||||
requestHolder.device.deviceRemove(it)
|
||||
}
|
||||
requestHolder.settingStore.userToken = ""
|
||||
// logout 操作:
|
||||
// 从服务器删除本设备
|
||||
// 删除保存的 token
|
||||
requestHolder.globalNavController.navigate("login") {
|
||||
requestHolder.globalNavController.popBackStack()
|
||||
}
|
||||
requestHolder.alert.alert(
|
||||
"提示",
|
||||
"由于厂商推送设备服务限制,暂时不支持更换为自建 PushDeer 服务器,但仅更换登陆账号并不会影响您的使用",
|
||||
{}
|
||||
)
|
||||
}
|
||||
}
|
||||
// item {
|
||||
|
@ -0,0 +1,30 @@
|
||||
package com.pushdeer.os.util
|
||||
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.wh.common.activity.QrScanActivity
|
||||
|
||||
object ActivityOpener {
|
||||
|
||||
fun forResult(activity: AppCompatActivity): ActivityResultLauncher<Intent> {
|
||||
return activity.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
Toast.makeText(
|
||||
activity,
|
||||
"${result.data?.getStringExtra(QrScanActivity.DataKey)}",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}
|
||||
|
||||
fun forPermission(activity: AppCompatActivity): ActivityResultLauncher<Array<String>> {
|
||||
return activity.registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {
|
||||
it.entries.forEach {
|
||||
Log.d("WH_", "forPermission:${it.key} ${it.value} ")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="85.84757"
|
||||
android:endY="92.4963"
|
||||
android:startX="42.9492"
|
||||
android:startY="49.59793"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0" />
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000" />
|
||||
</vector>
|
@ -1,170 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#3DDC84"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,0L9,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,0L19,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,0L29,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,0L39,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,0L49,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,0L59,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,0L69,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,0L79,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M89,0L89,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M99,0L99,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,9L108,9"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,19L108,19"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,29L108,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,39L108,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,49L108,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,59L108,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,69L108,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,79L108,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,89L108,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,99L108,99"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29L89,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,39L89,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,49L89,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,59L89,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,69L89,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,79L89,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,19L29,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,19L39,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,19L49,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,19L59,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,19L69,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,19L79,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
</vector>
|
29
android/app/src/main/res/drawable/ic_launcher_foreground.xml
Normal file
@ -0,0 +1,29 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<group android:scaleX="0.1981214"
|
||||
android:scaleY="0.1981214"
|
||||
android:translateX="33.056"
|
||||
android:translateY="30.277714">
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M0,0h233v233h-233z"/>
|
||||
<path
|
||||
android:pathData="M-282.333,375.018h26.8l-0.7,-14.526c1.7,-5.491 13.527,-40.982 44.275,-61.545q9.332,-6.241 17.071,-11.58h0a69.072,69.072 0,0 0,-5.244 7.935c-1.149,2.3 -3.8,7.636 26.856,67.089l-1.1,12.629h29.6l0.6,-4.293c1.048,-7.437 -4.992,-19.965 -14.474,-38.586 -2.744,-5.39 -5.292,-10.431 -7.186,-14.624h0a13.171,13.171 0,0 1,-1.546 -9.586,3.626 3.626,0 0,1 1.845,-1.894l1.2,-0.349 43.627,-41.73 3.694,1.348c19.366,7.635 30.947,9.982 74.574,9.186 2.246,9.982 8.234,34.491 14.976,44.922 -2.844,15.473 -5.741,48.67 -5.839,49.916l-0.55,5.689h27.5v-12.03a383.644,383.644 0,0 0,5.439 -49.017c-0.349,-8.635 1.2,-28.5 2.145,-39.581l34.042,19.965h0a24.254,24.254 0,0 1,9.234 12.228c2.747,9.533 16.723,64.143 16.873,64.442l0.947,3.743h23.61l1.4,-1.2c4.342,-3.743 3.095,-13.127 -3.695,-27.9h0a432.137,432.137 0,0 1,-17.67 -56.851c0,-2.893 -2.245,-11.18 -15.922,-19.965l0,0a76.686,76.686 0,0 0,-8.934 -4.989l-2.545,-1.247v0a57.934,57.934 0,0 0,25.257 -16.97A112.324,112.324 0,0 1,75.363 235.307a56.1,56.1 0,0 0,20.564 -30.8l9.982,-42.329c4.342,-0.25 8.736,-0.647 13.127,-1.149 5.891,-0.647 11.929,-1.3 17.52,-1.4 17.869,0 23.011,-2.594 27.851,-7.786s4.992,-21.761 2.4,-27.5l0,0a6.684,6.684 0,0 0,-4.99 -4.289c-13.377,-4.143 -32.593,-12.827 -34.94,-16.622 -3.993,-6.239 -20.466,-7.138 -35.79,-6.539l-9.036,-11.629 7.337,-3.746L134.31,88.007v-0.449h54.411L203.697,68.287l-7.938,-6.288 -11.88,15.372L139.454,77.371l5.94,-11.73L170.351,37.887l-7.437,-6.641 -20.766,23.21 -8.784,-14.074 -8.535,4.993 10.731,17.569 -7.089,13.725L94.53,71.677l6.389,-27.848 26.653,-25.707 -6.689,-7.19L98.77,32.246l-5.539,-15.623 -9.436,3.294 7.44,21.664L84.147,72.827l-9.982,4.993L51.702,64.993l11.131,-16.574 -8.287,-5.54L44.165,58.353l-14.976,-18.07L50.202,22.207l-6.539,-7.587L24.147,31.599l-11.33,-24.46 -9.036,4.5 12.28,26.856 -0.849,0.749 25.957,31.448 29.8,16.768 0.449,0.55c-8.287,-4.641 -16.671,-8.287 -21.761,-7.486v0a8.588,8.588 0,0 0,-7.388 9.036,33.934 33.934,0 0,0 8.736,19.317l-32.4,37.537a513.11,513.11 0,0 0,-82.812 8.234c-17.221,3.346 -38.137,1.348 -58.4,-0.6 -28.75,-2.642 -56.005,-5.288 -71.73,7.34a59.131,59.131 0,0 0,-12.629 13.778c-7.838,1.8 -29.951,11.233 -29.951,59.2v4.992h4.992a19.5,19.5 0,0 0,13.377 -7.089c0,4.443 0,8.983 0.3,13.628v3.942a33.606,33.606 0,0 1,-4.042 9.185,17.928 17.928,0 0,0 -3.294,9.982 163.081,163.081 0,0 0,-21.263 13.078l-1.1,0.749L-282.336,358.05ZM-169.72,296.948a13.677,13.677 0,0 0,-6.689 6.64,21.454 21.454,0 0,0 1.448,17.97c1.995,4.394 4.641,9.586 7.388,14.976h0A210.546,210.546 0,0 1,-154.698 364.934h-8.934l0.4,-4.693 -0.4,-1.2c-12.629,-24.408 -26.2,-53.659 -27.054,-59.9 1.1,-1.845 3.444,-4.993 5.742,-8.234a83.879,83.879 0,0 0,11.33 -18.718c7.586,-5.492 12.43,-9.185 14.377,-10.682a82.932,82.932 0,0 1,26.9 -0.3ZM-16.176,361.839v3.245h-6.689c1,-10.881 3.4,-35.24 5.64,-45.724l0.5,-2.347 -1.547,-1.845c-4.693,-5.689 -10.532,-26.054 -13.976,-40.832l23.61,-0.551c-0.947,11.33 -2.5,31.4 -2.145,40.633h0a397.657,397.657 0,0 1,-5.39 47.322ZM-226.624,226.274c1.149,-20.366 7.037,-30.748 12.58,-36.041a99.151,99.151 0,0 0,-4.095 24.31,50.532 50.532,0 0,1 -8.485,11.73ZM-272.348,360.199 L-239.698,289.421a109.45,109.45 0,0 1,21.162 -12.382l4.592,-1.246 -1.1,-4.593c-0.7,-3.095 0,-3.944 1.6,-6.988a43.328,43.328 0,0 0,5.288 -12.479v-6.037c-1,-34.293 -1.7,-59.049 19.965,-76.419 12.629,-9.982 37.837,-7.688 64.539,-4.992 20.965,1.995 42.628,4.094 61.246,0.448l0,0a502.892,502.892 0,0 1,83.46 -8.336h2.3l34.94,-40.633 0,0a28.239,28.239 0,0 0,11.58 5.39l1.846,-9.982a27.909,27.909 0,0 1,-15.971 -12.879,21.824 21.824,0 0,1 -3.5,-8.085c5.891,0.749 22.712,10.784 35.988,20.616l3.043,-4.143c13.078,-0.449 24.958,0.449 27.005,1.947 4.592,7.239 24.16,14.976 34.443,18.718h0a6.434,6.434 0,0 0,5.491 7.935,29.034 29.034,0 0,1 -1.3,9.635c-2.2,2.347 -4.042,4.394 -20.665,4.592a178.548,178.548 0,0 0,-18.52 1.448c-12.13,1.348 -23.61,2.594 -31.246,-1 -9.982,-4.992 -11.281,-10.382 -11.33,-10.431l-9.982,1.2c0,1.1 1.748,11.131 16.97,18.269h0a37,37 0,0 0,13.179 3.1l-9.185,39.933v0a46.837,46.837 0,0 1,-17.02 24.958l-0.9,0.7A229.149,229.149 0,0 1,83.202 194.932l4.641,-8.635 -14.976,2.047 9.982,-20.766 -8.934,-4.393 -18.269,38.137 14.077,-1.947C63.036,212.707 55.802,229.326 56.396,238.907c-7.785,7.635 -14.227,13.827 -25.606,14.976v0a50.516,50.516 0,0 1,-0.7 -14.373l-9.982,-0.55c-1.246,24.011 5.39,28.5 16.424,33.791h0a69.288,69.288 0,0 1,7.838 4.245c10.634,7.036 11.629,12.479 11.629,12.479v1.3c0.4,1.646 9.982,40.281 18.618,59.3l0,0a57.23,57.23 0,0 1,4.99 14.976L70.122,365.051c-3.245,-12.629 -13.575,-52.712 -15.922,-60.946v0a34.29,34.29 0,0 0,-13.624 -17.918l-57.7,-34.341 -4.993,8.586 5.892,3.5c-67.088,1.647 -76.719,0 -97.086,-7.987l0,0a89.857,89.857 0,0 0,-49.017 -3.942l-1.047,0.25 -0.849,0.647S-182.845,267.407 -217.389,290.519c-36.389,24.359 -48.168,66.238 -48.666,68.035v0.749l0.3,5.69L-272.347,364.993Z"
|
||||
android:fillColor="#3b4789"/>
|
||||
<path
|
||||
android:pathData="M110.502,119.904a5.39,5.39 0,1 1,-5.39 -5.394,5.39 5.39,0 0,1 5.39,5.394"
|
||||
android:fillColor="#3b4789"/>
|
||||
<path
|
||||
android:pathData="M-152.554,175.257l1,-9.986v0a50.958,50.958 0,0 0,-50.911 33.994l9.335,3.545h0a40.393,40.393 0,0 1,40.584 -27.555Z"
|
||||
android:fillColor="#3b4789"/>
|
||||
<path
|
||||
android:pathData="M153.592,151.55A2.54,2.54 83.016,0 0,150.072 151.982L124.335,184.905a2.54,2.54 83.016,0 0,0.431 3.52l53.994,42.208a2.54,2.54 83.016,0 0,3.52 -0.431L208.016,197.278A2.54,2.54 83.016,0 0,207.585 193.759ZM153.734,155.904L203.325,194.671L162.38,195.947ZM150.519,156.839 L155.87,181.674 128.916,184.473ZM203.196,198.018L181.593,225.652l-3.791,-26.831ZM156.586,184.954 L159.399,198.027a1.671,1.671 83.016,0 0,1.688 1.319L174.447,198.916 178.286,226.02L129.355,187.769Z"
|
||||
android:strokeWidth="2.0003998"
|
||||
android:fillColor="#3b4789"
|
||||
android:strokeColor="#3b4789"/>
|
||||
</group>
|
||||
</group>
|
||||
</vector>
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 1.4 KiB |
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 2.8 KiB |
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 982 B |
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 1.7 KiB |
BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 1.9 KiB |
BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 3.8 KiB |
BIN
android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 2.8 KiB |
BIN
android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 5.8 KiB |
BIN
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 7.9 KiB |
Before Width: | Height: | Size: 3.8 KiB |
BIN
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 7.6 KiB |
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#FFFFFF</color>
|
||||
</resources>
|
@ -48,4 +48,9 @@ dependencies {
|
||||
|
||||
implementation("com.squareup.okhttp3:okhttp:4.9.2")
|
||||
implementation 'com.google.code.gson:gson:2.8.9'
|
||||
|
||||
// qr
|
||||
implementation 'com.google.zxing:core:3.2.1'
|
||||
implementation 'cn.bingoogolapple:bga-qrcodecore:1.1.7@aar'
|
||||
implementation 'cn.bingoogolapple:bga-zxing:1.1.7@aar'
|
||||
}
|
@ -5,4 +5,6 @@
|
||||
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
|
||||
|
||||
|
||||
|
||||
|
||||
</manifest>
|
@ -0,0 +1,65 @@
|
||||
package com.wh.common.activity
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import cn.bingoogolapple.qrcode.core.QRCodeView
|
||||
import com.wh.common.R
|
||||
|
||||
|
||||
class QrScanActivity : AppCompatActivity(), QRCodeView.Delegate {
|
||||
|
||||
private val TAG = "WH_" + javaClass.simpleName
|
||||
private lateinit var qrCode: QRCodeView
|
||||
|
||||
companion object {
|
||||
val RequestCode_get_scan_result = 436
|
||||
val DataKey = "qr_scan_result"
|
||||
|
||||
fun forScanResultIntent(context: Context): Intent {
|
||||
return Intent(context, QrScanActivity::class.java).apply {
|
||||
putExtra(DataKey, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_qr_scan)
|
||||
qrCode = findViewById(R.id.qrcode1)
|
||||
qrCode.setDelegate(this)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
Log.d(TAG, "onStart")
|
||||
qrCode.startSpotAndShowRect()
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
Log.d(TAG, "onStop")
|
||||
qrCode.stopCamera()
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
qrCode.onDestroy()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun onScanQRCodeSuccess(result: String?) {
|
||||
Log.d(TAG, "onScanQRCodeSuccess: $result")
|
||||
qrCode.stopCamera()
|
||||
val intent = Intent()
|
||||
intent.putExtra(DataKey, result)
|
||||
setResult(RequestCode_get_scan_result, intent)
|
||||
finish()
|
||||
}
|
||||
|
||||
override fun onScanQRCodeOpenCameraError() {
|
||||
Log.e(TAG, "onScanQRCodeOpenCameraError")
|
||||
qrCode.startSpotAndShowRect()
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package com.wh.common.util
|
||||
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.wh.common.activity.QrScanActivity
|
||||
|
||||
object ActivityOpener {
|
||||
|
||||
fun forQrScanResult(
|
||||
activity: AppCompatActivity,
|
||||
onReturn: (String) -> Unit = {}
|
||||
): ActivityResultLauncher<Intent> {
|
||||
return activity.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
result.data?.getStringExtra(QrScanActivity.DataKey)?.let {
|
||||
onReturn(it)
|
||||
Toast.makeText(activity, it, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun forPermission(
|
||||
activity: AppCompatActivity,
|
||||
onReturn: () -> Unit = {}
|
||||
): ActivityResultLauncher<Array<String>> {
|
||||
return activity.registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {
|
||||
it.entries.forEach {
|
||||
Log.d("WH_", "forPermission:${it.key} ${it.value} ")
|
||||
}
|
||||
if (it.entries.all { it.value == true }){
|
||||
onReturn()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package com.wh.common.util;
|
||||
|
||||
|
||||
import static android.graphics.Color.BLACK;
|
||||
import static android.graphics.Color.WHITE;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.EncodeHintType;
|
||||
import com.google.zxing.MultiFormatWriter;
|
||||
import com.google.zxing.WriterException;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class QRCodeGenerator {
|
||||
private final Map<EncodeHintType, String> hints;
|
||||
private Bitmap bitmap = null;
|
||||
private final String str;
|
||||
private final int WIDTH;
|
||||
private final int HEIGHT;
|
||||
|
||||
public QRCodeGenerator(String str, int WIDTH, int HEIGHT){
|
||||
this.str = (str.length()>300)?"str is too long":str;
|
||||
this.WIDTH=WIDTH;
|
||||
this.HEIGHT=HEIGHT;
|
||||
this.hints = new HashMap<>();
|
||||
this.hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
|
||||
}
|
||||
|
||||
public Bitmap getQRCode() {
|
||||
try {
|
||||
BitMatrix Result = new MultiFormatWriter().encode(str, BarcodeFormat.QR_CODE, WIDTH, HEIGHT, hints);//通过字符串创建二维矩阵
|
||||
int width = Result.getWidth();
|
||||
int height = Result.getHeight();
|
||||
|
||||
int[] pixels = new int[width * height];
|
||||
for (int y = 0; y < height; y++) {
|
||||
int offset = y * width;
|
||||
for (int x = 0; x < width; x++) {
|
||||
pixels[offset + x] = Result.get(x, y) ? BLACK : WHITE;//根据二维矩阵数据创建数组
|
||||
}
|
||||
}
|
||||
bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);//创建位图
|
||||
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);//将数组加载到位图中
|
||||
return bitmap;
|
||||
} catch (WriterException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
}
|
46
android/common/src/main/res/layout/activity_qr_scan.xml
Normal file
@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@android:color/white"
|
||||
tools:ignore="NewApi">
|
||||
|
||||
<cn.bingoogolapple.qrcode.zxing.ZXingView
|
||||
android:id="@+id/qrcode1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:qrcv_animTime="300"
|
||||
app:qrcv_barCodeTipText="将条码放入框内,即可自动扫描"
|
||||
app:qrcv_barcodeRectHeight="40dp"
|
||||
app:qrcv_borderColor="@android:color/black"
|
||||
app:qrcv_borderSize="0.1dp"
|
||||
app:qrcv_cornerColor="@android:color/black"
|
||||
app:qrcv_cornerLength="20dp"
|
||||
app:qrcv_cornerSize="3dp"
|
||||
app:qrcv_isBarcode="false"
|
||||
app:qrcv_isCenterVertical="false"
|
||||
app:qrcv_isOnlyDecodeScanBoxArea="true"
|
||||
app:qrcv_isScanLineReverse="true"
|
||||
app:qrcv_isShowDefaultGridScanLineDrawable="false"
|
||||
app:qrcv_isShowDefaultScanLineDrawable="true"
|
||||
app:qrcv_isShowTipBackground="false"
|
||||
app:qrcv_isShowTipTextAsSingleLine="false"
|
||||
app:qrcv_isTipTextBelowRect="true"
|
||||
app:qrcv_maskColor="#DEBCBCBC"
|
||||
app:qrcv_qrCodeTipText="请将QRCode放到扫描框中"
|
||||
app:qrcv_rectWidth="240dp"
|
||||
app:qrcv_scanLineColor="@android:color/black"
|
||||
app:qrcv_scanLineMargin="0dp"
|
||||
app:qrcv_scanLineSize="0.5dp"
|
||||
app:qrcv_tipTextColor="#80ffffff"
|
||||
app:qrcv_tipTextSize="14sp"
|
||||
app:qrcv_toolbarHeight="40dp"
|
||||
app:qrcv_topOffset="80dp" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -2,4 +2,5 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.wh.sbw.compose">
|
||||
|
||||
|
||||
</manifest>
|
1
android/pushdeercommon/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/build
|
47
android/pushdeercommon/build.gradle
Normal file
@ -0,0 +1,47 @@
|
||||
plugins {
|
||||
id 'com.android.library'
|
||||
id 'kotlin-android'
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdk 32
|
||||
|
||||
defaultConfig {
|
||||
minSdk 21
|
||||
targetSdk 32
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles "consumer-rules.pro"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
implementation 'androidx.core:core-ktx:1.7.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.4.1'
|
||||
implementation 'com.google.android.material:material:1.5.0'
|
||||
testImplementation 'junit:junit:4.+'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
||||
|
||||
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
|
||||
implementation 'com.squareup.retrofit2:converter-scalars:2.0.0'
|
||||
implementation 'com.google.code.gson:gson:2.8.9'
|
||||
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
|
||||
}
|
0
android/pushdeercommon/consumer-rules.pro
Normal file
21
android/pushdeercommon/proguard-rules.pro
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
@ -0,0 +1,24 @@
|
||||
package com.pushdeer.common
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ExampleInstrumentedTest {
|
||||
@Test
|
||||
fun useAppContext() {
|
||||
// Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("com.pushdeer.common.test", appContext.packageName)
|
||||
}
|
||||
}
|
5
android/pushdeercommon/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.pushdeer.common">
|
||||
|
||||
</manifest>
|
@ -0,0 +1,93 @@
|
||||
package com.pushdeer.common.api
|
||||
|
||||
import com.pushdeer.common.api.data.response.*
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
import retrofit2.converter.scalars.ScalarsConverterFactory
|
||||
import retrofit2.http.Field
|
||||
import retrofit2.http.FieldMap
|
||||
import retrofit2.http.FormUrlEncoded
|
||||
import retrofit2.http.POST
|
||||
|
||||
interface PushDeerApi {
|
||||
companion object {
|
||||
private const val baseUrl = "https://api2.pushdeer.com"
|
||||
|
||||
fun create(): PushDeerApi {
|
||||
return Retrofit.Builder()
|
||||
.baseUrl(baseUrl)
|
||||
.addConverterFactory(ScalarsConverterFactory.create())
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.build()
|
||||
.create(PushDeerApi::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("/login/idtoken")
|
||||
suspend fun loginIdToken(@Field("idToken") idToken: String): ReturnData<TokenOnly>
|
||||
|
||||
// @GET("/login/fake")
|
||||
// suspend fun fakeLogin(): ReturnData<TokenOnly>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("/user/info")
|
||||
suspend fun userInfo(@Field("token") token: String): ReturnData<UserInfo>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("/device/reg")
|
||||
suspend fun deviceReg(@FieldMap data: Map<String, String>): ReturnData<DeviceInfoList>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("/device/list")
|
||||
suspend fun deviceList(@Field("token") token: String): ReturnData<DeviceInfoList>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("/device/remove")
|
||||
suspend fun deviceRemove(@Field("token") token: String, @Field("id") id: Int): String
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("/device/rename")
|
||||
suspend fun deviceRename(
|
||||
@Field("token") token: String,
|
||||
@Field("id") id: Int,
|
||||
@Field("name") newName: String
|
||||
): String
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("/key/gen")
|
||||
suspend fun keyGen(@Field("token") token: String): ReturnData<PushKeyList>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("/key/regen")
|
||||
suspend fun keyRegen(@FieldMap data: Map<String, String>): String
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("/key/list")
|
||||
suspend fun keyList(@Field("token") token: String): ReturnData<PushKeyList>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("/key/remove")
|
||||
suspend fun keyRemove(@FieldMap data: Map<String, String>): String
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("/key/rename")
|
||||
suspend fun keyRename(
|
||||
@Field("token") token: String,
|
||||
@Field("id") id: String,
|
||||
@Field("name") newName: String
|
||||
): String
|
||||
|
||||
// pushkey text desp type:text/image/markdown
|
||||
@FormUrlEncoded
|
||||
@POST("/message/push")
|
||||
suspend fun messagePush(@FieldMap data: Map<String, String>): String
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("/message/list")
|
||||
suspend fun messageList(@Field("token") token: String): ReturnData<MessageList>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("/message/remove")
|
||||
suspend fun messageRemove(@Field("token") token: String, @Field("id") id: Int): String
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package com.pushdeer.common.api.data.request
|
||||
|
||||
class DeviceInfo {
|
||||
var id:Int = 0
|
||||
var uid:String = ""
|
||||
var name:String = ""
|
||||
var type:String = ""
|
||||
var device_id: String = ""
|
||||
var is_clip: Int = 0
|
||||
|
||||
fun toRequestMap(token:String): Map<String, String> {
|
||||
return mapOf(
|
||||
"token" to token,
|
||||
"name" to name,
|
||||
"device_id" to device_id,
|
||||
"is_clip" to is_clip.toString(),
|
||||
"type" to "android"
|
||||
)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "id:$id uid:$uid name:$name type:$type device_id:$device_id is_clip:$is_clip"
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.pushdeer.common.api.data.response
|
||||
|
||||
import com.pushdeer.common.api.data.request.DeviceInfo
|
||||
|
||||
|
||||
class DeviceInfoList{
|
||||
var devices:List<DeviceInfo> = emptyList()
|
||||
|
||||
override fun toString(): String {
|
||||
return "devices:$devices"
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package com.pushdeer.common.api.data.response
|
||||
|
||||
|
||||
class Message {
|
||||
var id = 0
|
||||
var uid: String? = null
|
||||
var text: String? = null
|
||||
var desp: String? = null
|
||||
var type: String? = null
|
||||
var pushkey_name: String? = null
|
||||
var created_at: String? = null
|
||||
}
|
||||
|
||||
class MessageList {
|
||||
var messages = emptyList<Message>()
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.pushdeer.common.api.data.response
|
||||
|
||||
class PushKey {
|
||||
var id:String = ""
|
||||
var key: String = ""
|
||||
var name: String = ""
|
||||
var created_at = ""
|
||||
|
||||
override fun toString(): String {
|
||||
return "id:$id key:$key name:$name created_at:$created_at"
|
||||
}
|
||||
}
|
||||
|
||||
class PushKeyList {
|
||||
var keys: List<PushKey> = emptyList()
|
||||
|
||||
override fun toString(): String {
|
||||
return "keys:$keys"
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.pushdeer.common.api.data.response
|
||||
|
||||
class ReturnData<T> {
|
||||
var code: Int = 0
|
||||
var content: T?=null
|
||||
var error:String = ""
|
||||
|
||||
override fun toString(): String {
|
||||
return "code:${code} error:${error} content:${content.toString()}"
|
||||
}
|
||||
}
|
||||
|
||||
class TokenOnly{
|
||||
var token:String = ""
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.pushdeer.common.api.data.response
|
||||
|
||||
class UserInfo {
|
||||
var id: String = ""
|
||||
var name: String = ""
|
||||
var email: String = ""
|
||||
var app_id: String = ""
|
||||
var wechat_id: String = ""
|
||||
var level: Int = 1
|
||||
var created_at: String = ""
|
||||
var updated_at: String = ""
|
||||
|
||||
override fun toString(): String {
|
||||
return "id:$id\n" +
|
||||
"name:$name\n" +
|
||||
"email:$email\n" +
|
||||
"app_id:$app_id\n" +
|
||||
"wechat_id:$wechat_id\n" +
|
||||
"level:$level\n" +
|
||||
"created:$created_at\n" +
|
||||
"updated:$updated_at"
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.pushdeer.common
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
class ExampleUnitTest {
|
||||
@Test
|
||||
fun addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2)
|
||||
}
|
||||
}
|
@ -11,3 +11,4 @@ rootProject.name = "PushDeer"
|
||||
include ':app'
|
||||
include ':common'
|
||||
include ':compose'
|
||||
include ':pushdeercommon'
|
||||
|