修改icon,完善注销逻辑,增加点击MessageListItem复制文本功能
@ -13,6 +13,8 @@
|
|||||||
<option value="$PROJECT_DIR$/app" />
|
<option value="$PROJECT_DIR$/app" />
|
||||||
<option value="$PROJECT_DIR$/common" />
|
<option value="$PROJECT_DIR$/common" />
|
||||||
<option value="$PROJECT_DIR$/compose" />
|
<option value="$PROJECT_DIR$/compose" />
|
||||||
|
<option value="$PROJECT_DIR$/pushdeerclient" />
|
||||||
|
<option value="$PROJECT_DIR$/pushdeercommon" />
|
||||||
</set>
|
</set>
|
||||||
</option>
|
</option>
|
||||||
<option name="resolveModulePerSourceSet" value="false" />
|
<option name="resolveModulePerSourceSet" value="false" />
|
||||||
|
@ -14,8 +14,13 @@
|
|||||||
<entry key="../../../../layout/compose-model-1641659962289.xml" value="2.0" />
|
<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-1641694023752.xml" value="0.1" />
|
||||||
<entry key="../../../../layout/compose-model-1642733328920.xml" value="2.0" />
|
<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/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/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>
|
</map>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
|
@ -1,32 +1,34 @@
|
|||||||
# PushDeer for Android
|
# PushDeer for Android
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 适配进度
|
### 适配进度
|
||||||
|
|
||||||
* MiPush(状态:已调通、已接入)
|
* MiPush(状态:已调通、已接入)
|
||||||
* miui 12.5.6 正常
|
* miui √
|
||||||
* 原生、类原生 可成功注册,无法收到推送,可能和地区识别有关,待解决
|
* Mokee √
|
||||||
* miui下处于"几乎可用"的状态,已接入 appleId
|
* HuaWei √
|
||||||
|
* 部分原生、类原生 可成功注册,无法收到推送,可能和地区识别有关,待解决
|
||||||
|
|
||||||
### TODO
|
### TODO
|
||||||
|
|
||||||
* ~~调通 MiPush~~
|
* ~~调通 MiPush~~
|
||||||
* ~~接入 MiPush~~
|
* ~~接入 MiPush~~
|
||||||
* 完善 log ~~采集~~ 回传机制,便于调试
|
* 完善 log ~~采集~~ 回传机制,便于调试
|
||||||
* 测试不同厂商设备上的通知推送效果
|
* 测试不同厂商设备/系统上的通知推送效果 miui√ Mokee√ HuaWei√
|
||||||
* ~~接入 PushDeer~~
|
* ~~接入 PushDeer~~
|
||||||
* ~~界面设计:BottomBar+Navigation(Device Key Message Setting)~~
|
* ~~界面设计:BottomBar+Navigation(Device Key Message Setting)~~
|
||||||
* 调整 KeyList MessageList 等处的自定义绘制
|
* 调整 KeyList MessageList 等处的自定义绘制
|
||||||
* ~~增加 DeviceList 外的侧滑手势~~
|
* ~~增加 DeviceList 外的侧滑手势~~
|
||||||
* ~~增加侧滑手势相关动作~~
|
* ~~增加侧滑手势相关动作~~
|
||||||
* 增加各种操作前的二次确认弹窗,包括自动登陆
|
* 增加手动修改服务器地址逻辑(并放置到登陆界面)
|
||||||
* 增加非Miui设备的权限获取
|
* ~~增加退出登陆的逻辑~~
|
||||||
* 增加手动修改服务器地址/退出登陆的逻辑(并放置到登陆界面)
|
|
||||||
* 增加登陆过程中的图形提示
|
* 增加登陆过程中的图形提示
|
||||||
* 增加对PushKey重命名的逻辑
|
* ~~增加对PushKey重命名的逻辑~~
|
||||||
* 增加对设备重命名的逻辑
|
* ~~增加对设备重命名的逻辑~~
|
||||||
* 增加长按复制消息内容的逻辑
|
* ~~增加长按复制消息内容的逻辑~~
|
||||||
|
* 增加点击设置界面用户名修改用户名逻辑
|
||||||
|
* ~~适配image类型的消息显示~~
|
||||||
|
* ~~修改app图标~~
|
||||||
|
|
||||||
|
|
||||||
### 日志
|
### 日志
|
||||||
|
|
||||||
@ -105,6 +107,12 @@
|
|||||||
* 修改登陆界面ui
|
* 修改登陆界面ui
|
||||||
* 增加key/device的重命名逻辑
|
* 增加key/device的重命名逻辑
|
||||||
* 适配英语和中文
|
* 适配英语和中文
|
||||||
|
* 增加点击PushKey显示二维码功能
|
||||||
|
|
||||||
|
* 2022-01-22
|
||||||
|
* 增加点击 Message 列表项目复制文本功能
|
||||||
|
* 增加适配Image类型Message的显示
|
||||||
|
* 完善登陆注销逻辑
|
||||||
|
|
||||||
|
|
||||||
### 感谢
|
### 感谢
|
||||||
|
@ -91,11 +91,12 @@ dependencies {
|
|||||||
implementation "androidx.room:room-runtime:$room_version"
|
implementation "androidx.room:room-runtime:$room_version"
|
||||||
kapt "androidx.room:room-compiler:$room_version"
|
kapt "androidx.room:room-compiler:$room_version"
|
||||||
|
|
||||||
|
// qr
|
||||||
implementation 'com.google.zxing:core:3.2.1'
|
implementation 'com.google.zxing:core:3.2.1'
|
||||||
implementation 'cn.bingoogolapple:bga-qrcodecore:1.1.7@aar'
|
implementation 'cn.bingoogolapple:bga-qrcodecore:1.1.7@aar'
|
||||||
implementation 'cn.bingoogolapple:bga-zxing: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'
|
final def markwon_version = '4.6.2'
|
||||||
implementation "io.noties.markwon:core:$markwon_version"
|
implementation "io.noties.markwon:core:$markwon_version"
|
||||||
|
@ -4,12 +4,13 @@
|
|||||||
package="com.pushdeer.os">
|
package="com.pushdeer.os">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
<!-- <uses-permission android:name="android.permission.READ_PHONE_STATE" />-->
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
<!-- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"-->
|
||||||
tools:ignore="ScopedStorage" />
|
<!-- tools:ignore="ScopedStorage" />-->
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
|
||||||
@ -18,8 +19,9 @@
|
|||||||
android:protectionLevel="signature" />
|
android:protectionLevel="signature" />
|
||||||
<uses-permission android:name="com.pushdeer.os.permission.MIPUSH_RECEIVE" />
|
<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.autofocus" />
|
||||||
<uses-feature android:name="android.hardware.camera" />
|
<uses-feature android:name="android.hardware.camera" />
|
||||||
|
|
||||||
@ -49,11 +51,11 @@
|
|||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:screenOrientation="portrait"
|
android:screenOrientation="portrait"
|
||||||
android:name=".activity.QrScanActivity"
|
android:name="com.wh.common.activity.QrScanActivity"
|
||||||
android:theme="@style/Theme.PushDeer.NoActionBar"
|
android:theme="@style/Theme.PushDeer.NoActionBar"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- start -->
|
<!-- miPush components start -->
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name="com.xiaomi.push.service.XMPushService"
|
android:name="com.xiaomi.push.service.XMPushService"
|
||||||
@ -86,7 +88,7 @@
|
|||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
<!-- end -->
|
<!-- miPush components end -->
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
android:name="com.xiaomi.push.service.receivers.PingReceiver"
|
android:name="com.xiaomi.push.service.receivers.PingReceiver"
|
||||||
@ -101,7 +103,6 @@
|
|||||||
<receiver
|
<receiver
|
||||||
android:name="com.pushdeer.os.receiver.MessageReceiver"
|
android:name="com.pushdeer.os.receiver.MessageReceiver"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
<!--这里com.xiaomi.mipushdemo.DemoMessageRreceiver改成app中定义的完整类名-->
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="com.xiaomi.mipush.RECEIVE_MESSAGE" />
|
<action android:name="com.xiaomi.mipush.RECEIVE_MESSAGE" />
|
||||||
</intent-filter>
|
</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.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.util.Linkify
|
import android.text.util.Linkify
|
||||||
import android.widget.Toast
|
|
||||||
import androidx.activity.ComponentActivity
|
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.compose.animation.ExperimentalAnimationApi
|
import androidx.compose.animation.ExperimentalAnimationApi
|
||||||
@ -29,7 +26,6 @@ import coil.ImageLoader
|
|||||||
import com.google.accompanist.insets.ProvideWindowInsets
|
import com.google.accompanist.insets.ProvideWindowInsets
|
||||||
import com.google.accompanist.insets.statusBarsPadding
|
import com.google.accompanist.insets.statusBarsPadding
|
||||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||||
import com.pushdeer.os.activity.QrScanActivity
|
|
||||||
import com.pushdeer.os.holder.RequestHolder
|
import com.pushdeer.os.holder.RequestHolder
|
||||||
import com.pushdeer.os.store.SettingStore
|
import com.pushdeer.os.store.SettingStore
|
||||||
import com.pushdeer.os.ui.compose.componment.MyAlertDialog
|
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.LoginPage
|
||||||
import com.pushdeer.os.ui.compose.page.main.MainPage
|
import com.pushdeer.os.ui.compose.page.main.MainPage
|
||||||
import com.pushdeer.os.ui.theme.PushDeerTheme
|
import com.pushdeer.os.ui.theme.PushDeerTheme
|
||||||
|
import com.pushdeer.os.util.ActivityOpener
|
||||||
import com.pushdeer.os.util.SystemUtil
|
import com.pushdeer.os.util.SystemUtil
|
||||||
import com.pushdeer.os.viewmodel.LogDogViewModel
|
import com.pushdeer.os.viewmodel.LogDogViewModel
|
||||||
import com.pushdeer.os.viewmodel.MessageViewModel
|
import com.pushdeer.os.viewmodel.MessageViewModel
|
||||||
import com.pushdeer.os.viewmodel.PushDeerViewModel
|
import com.pushdeer.os.viewmodel.PushDeerViewModel
|
||||||
import com.pushdeer.os.viewmodel.UiViewModel
|
import com.pushdeer.os.viewmodel.UiViewModel
|
||||||
import com.wh.common.util.UiUtils
|
|
||||||
import io.noties.markwon.Markwon
|
import io.noties.markwon.Markwon
|
||||||
import io.noties.markwon.image.coil.CoilImagesPlugin
|
import io.noties.markwon.image.coil.CoilImagesPlugin
|
||||||
import io.noties.markwon.linkify.LinkifyPlugin
|
import io.noties.markwon.linkify.LinkifyPlugin
|
||||||
@ -62,18 +58,36 @@ class MainActivity : AppCompatActivity(), RequestHolder {
|
|||||||
override val messageViewModel: MessageViewModel by viewModels { viewModelFactory }
|
override val messageViewModel: MessageViewModel by viewModels { viewModelFactory }
|
||||||
override val settingStore: SettingStore by lazy { (application as App).storeKeeper.settingStore }
|
override val settingStore: SettingStore by lazy { (application as App).storeKeeper.settingStore }
|
||||||
override val fragmentManager: FragmentManager by lazy { this.supportFragmentManager }
|
override val fragmentManager: FragmentManager by lazy { this.supportFragmentManager }
|
||||||
// override val resource: Resources by lazy { this.resource }
|
|
||||||
|
|
||||||
override val coilImageLoader: ImageLoader by lazy {
|
override val coilImageLoader: ImageLoader by lazy {
|
||||||
ImageLoader.Builder(this)
|
ImageLoader.Builder(this)
|
||||||
.apply {
|
.apply {
|
||||||
availableMemoryPercentage(0.5)
|
availableMemoryPercentage(0.5)
|
||||||
bitmapPoolPercentage(0.5)
|
bitmapPoolPercentage(0.5)
|
||||||
crossfade(true)
|
crossfade(750)
|
||||||
|
allowHardware(true)
|
||||||
}
|
}
|
||||||
.build()
|
.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 {
|
override val markdown: Markwon by lazy {
|
||||||
Markwon.builder(this)
|
Markwon.builder(this)
|
||||||
@ -84,10 +98,9 @@ class MainActivity : AppCompatActivity(), RequestHolder {
|
|||||||
|
|
||||||
override lateinit var globalNavController: NavHostController
|
override lateinit var globalNavController: NavHostController
|
||||||
override lateinit var coroutineScope: CoroutineScope
|
override lateinit var coroutineScope: CoroutineScope
|
||||||
override lateinit var myActivity: ComponentActivity
|
override lateinit var myActivity: AppCompatActivity
|
||||||
override val clipboardManager by lazy { getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager }
|
override lateinit var qrScanActivityOpener: ActivityResultLauncher<Intent>
|
||||||
|
override lateinit var requestPermissionOpener: ActivityResultLauncher<Array<String>>
|
||||||
override lateinit var activityOpener: ActivityResultLauncher<Intent>
|
|
||||||
|
|
||||||
@ExperimentalAnimationApi
|
@ExperimentalAnimationApi
|
||||||
@ExperimentalMaterialApi
|
@ExperimentalMaterialApi
|
||||||
@ -95,28 +108,23 @@ class MainActivity : AppCompatActivity(), RequestHolder {
|
|||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
myActivity = this
|
myActivity = this
|
||||||
activityOpener =
|
qrScanActivityOpener = ActivityOpener.forResult(this)
|
||||||
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
requestPermissionOpener = ActivityOpener.forPermission(this)
|
||||||
Toast.makeText(
|
|
||||||
this,
|
|
||||||
"${result.data?.getStringExtra(QrScanActivity.DataKey)}",
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
|
|
||||||
UiUtils.keepScreenOn(window)
|
|
||||||
setContent {
|
setContent {
|
||||||
globalNavController = rememberNavController()
|
globalNavController = rememberNavController()
|
||||||
coroutineScope = rememberCoroutineScope()
|
coroutineScope = rememberCoroutineScope()
|
||||||
val useDarkIcons = MaterialTheme.colors.isLight
|
val useDarkIcons = MaterialTheme.colors.isLight
|
||||||
val systemUiController = rememberSystemUiController()
|
val systemUiController = rememberSystemUiController()
|
||||||
when {
|
when {
|
||||||
SystemUtil.isMiui() -> systemUiController.setStatusBarColor(Color.Transparent, useDarkIcons)
|
SystemUtil.isMiui() -> systemUiController.setStatusBarColor(
|
||||||
|
Color.Transparent,
|
||||||
|
useDarkIcons
|
||||||
|
)
|
||||||
else -> systemUiController.setSystemBarsColor(Color.Transparent, useDarkIcons)
|
else -> systemUiController.setSystemBarsColor(Color.Transparent, useDarkIcons)
|
||||||
}
|
}
|
||||||
WindowCompat.setDecorFitsSystemWindows(window, true)
|
WindowCompat.setDecorFitsSystemWindows(window, true)
|
||||||
miPushRepository.regId.observe(this) {
|
miPushRepository.regId.observe(this) {
|
||||||
// 这个操作放到注册成功后进行
|
|
||||||
settingStore.thisDeviceId = it
|
settingStore.thisDeviceId = it
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,66 +1,66 @@
|
|||||||
package com.pushdeer.os.activity
|
//package com.pushdeer.os.activity
|
||||||
|
//
|
||||||
|
//
|
||||||
import android.content.Context
|
//import android.content.Context
|
||||||
import android.content.Intent
|
//import android.content.Intent
|
||||||
import android.os.Bundle
|
//import android.os.Bundle
|
||||||
import android.util.Log
|
//import android.util.Log
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
//import androidx.appcompat.app.AppCompatActivity
|
||||||
import cn.bingoogolapple.qrcode.core.QRCodeView
|
//import cn.bingoogolapple.qrcode.core.QRCodeView
|
||||||
import com.pushdeer.os.R
|
//import com.pushdeer.os.R
|
||||||
|
//
|
||||||
|
//
|
||||||
class QrScanActivity : AppCompatActivity(), QRCodeView.Delegate {
|
//class QrScanActivity : AppCompatActivity(), QRCodeView.Delegate {
|
||||||
|
//
|
||||||
private val TAG = "WH_" + javaClass.simpleName
|
// private val TAG = "WH_" + javaClass.simpleName
|
||||||
private lateinit var qrCode: QRCodeView
|
// private lateinit var qrCode: QRCodeView
|
||||||
|
//
|
||||||
companion object {
|
// companion object {
|
||||||
val RequestCode_get_scan_result = 436
|
// val RequestCode_get_scan_result = 436
|
||||||
val DataKey = "qr_scan_result"
|
// val DataKey = "qr_scan_result"
|
||||||
|
//
|
||||||
fun forScanResultIntent(context: Context): Intent {
|
// fun forScanResultIntent(context: Context): Intent {
|
||||||
return Intent(context, QrScanActivity::class.java).apply {
|
// return Intent(context, QrScanActivity::class.java).apply {
|
||||||
putExtra(DataKey, 1)
|
// putExtra(DataKey, 1)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
// override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
// super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_qr_scan)
|
// setContentView(R.layout.activity_qr_scan)
|
||||||
qrCode = findViewById(R.id.qrcode1)
|
// qrCode = findViewById(R.id.qrcode1)
|
||||||
qrCode.setDelegate(this)
|
// qrCode.setDelegate(this)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onStart() {
|
// override fun onStart() {
|
||||||
super.onStart()
|
// super.onStart()
|
||||||
Log.d(TAG, "onStart")
|
// Log.d(TAG, "onStart")
|
||||||
qrCode.startSpotAndShowRect()
|
// qrCode.startSpotAndShowRect()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onStop() {
|
// override fun onStop() {
|
||||||
Log.d(TAG, "onStop")
|
// Log.d(TAG, "onStop")
|
||||||
qrCode.stopCamera()
|
// qrCode.stopCamera()
|
||||||
super.onStop()
|
// super.onStop()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onDestroy() {
|
// override fun onDestroy() {
|
||||||
qrCode.onDestroy()
|
// qrCode.onDestroy()
|
||||||
super.onDestroy()
|
// super.onDestroy()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onScanQRCodeSuccess(result: String?) {
|
// override fun onScanQRCodeSuccess(result: String?) {
|
||||||
Log.d(TAG, "onScanQRCodeSuccess: $result")
|
// Log.d(TAG, "onScanQRCodeSuccess: $result")
|
||||||
qrCode.stopCamera()
|
// qrCode.stopCamera()
|
||||||
val intent = Intent()
|
// val intent = Intent()
|
||||||
intent.putExtra(DataKey, result)
|
// intent.putExtra(DataKey, result)
|
||||||
setResult(RequestCode_get_scan_result, intent)
|
// setResult(RequestCode_get_scan_result, intent)
|
||||||
finish()
|
// finish()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onScanQRCodeOpenCameraError() {
|
// override fun onScanQRCodeOpenCameraError() {
|
||||||
Log.e(TAG, "onScanQRCodeOpenCameraError")
|
// Log.e(TAG, "onScanQRCodeOpenCameraError")
|
||||||
qrCode.startSpotAndShowRect()
|
// qrCode.startSpotAndShowRect()
|
||||||
}
|
// }
|
||||||
}
|
//}
|
@ -4,9 +4,9 @@ import android.content.ClipData
|
|||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import androidx.activity.ComponentActivity
|
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.compose.material.Text
|
import androidx.compose.material.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
@ -15,7 +15,6 @@ import androidx.fragment.app.FragmentManager
|
|||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
import coil.ImageLoader
|
import coil.ImageLoader
|
||||||
import com.pushdeer.os.R
|
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.request.DeviceInfo
|
||||||
import com.pushdeer.os.data.api.data.response.Message
|
import com.pushdeer.os.data.api.data.response.Message
|
||||||
import com.pushdeer.os.data.api.data.response.PushKey
|
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.MessageViewModel
|
||||||
import com.pushdeer.os.viewmodel.PushDeerViewModel
|
import com.pushdeer.os.viewmodel.PushDeerViewModel
|
||||||
import com.pushdeer.os.viewmodel.UiViewModel
|
import com.pushdeer.os.viewmodel.UiViewModel
|
||||||
|
import com.wh.common.activity.QrScanActivity
|
||||||
import io.noties.markwon.Markwon
|
import io.noties.markwon.Markwon
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
@ -37,106 +37,22 @@ interface RequestHolder {
|
|||||||
val settingStore: SettingStore
|
val settingStore: SettingStore
|
||||||
val globalNavController: NavHostController
|
val globalNavController: NavHostController
|
||||||
val coroutineScope: CoroutineScope
|
val coroutineScope: CoroutineScope
|
||||||
val myActivity: ComponentActivity
|
val myActivity: AppCompatActivity
|
||||||
val markdown: Markwon
|
val markdown: Markwon
|
||||||
val activityOpener: ActivityResultLauncher<Intent>
|
val qrScanActivityOpener: ActivityResultLauncher<Intent>
|
||||||
|
val requestPermissionOpener:ActivityResultLauncher<Array<String>>
|
||||||
val coilImageLoader: ImageLoader
|
val coilImageLoader: ImageLoader
|
||||||
|
|
||||||
// val resource:Resources
|
|
||||||
|
|
||||||
val fragmentManager: FragmentManager
|
val fragmentManager: FragmentManager
|
||||||
|
|
||||||
val alert: AlertRequest
|
val alert: AlertRequest
|
||||||
|
val key:KeyRequest
|
||||||
val clipboardManager: ClipboardManager
|
val device:DeviceRequest
|
||||||
|
val message:MessageRequest
|
||||||
fun copyPlainString(str: String) {
|
val clip:ClipRequest
|
||||||
clipboardManager.setPrimaryClip(ClipData.newPlainText("pushdeer-pushkey", str))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun startQrScanActivity() {
|
fun startQrScanActivity() {
|
||||||
activityOpener.launch(QrScanActivity.forScanResultIntent(myActivity))
|
qrScanActivityOpener.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()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toggleMessageSender() {
|
fun toggleMessageSender() {
|
||||||
@ -145,8 +61,20 @@ interface RequestHolder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun clearLogDog() {
|
fun clearLogDog() {
|
||||||
coroutineScope.launch {
|
alert.alert(R.string.global_alert_title_confirm,"Clear?",onOk = {
|
||||||
logDogViewModel.clear()
|
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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,9 +116,105 @@ interface RequestHolder {
|
|||||||
@StringRes title: Int,
|
@StringRes title: Int,
|
||||||
content: @Composable () -> Unit,
|
content: @Composable () -> Unit,
|
||||||
onOk: () -> Unit,
|
onOk: () -> Unit,
|
||||||
onCancel: () -> Unit={}
|
onCancel: () -> Unit = {}
|
||||||
|
) {
|
||||||
|
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)
|
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
|
@ExperimentalMaterialApi
|
||||||
@Composable
|
@Composable
|
||||||
fun CardItemWithContent(onClick: () -> Unit = {}, content: @Composable () -> Unit = {}) {
|
fun CardItemWithContent(onClick: () -> Unit, content: @Composable () -> Unit = {}) {
|
||||||
Card(
|
Card(
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
shape = RoundedCornerShape(4.dp),
|
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
|
@Composable
|
||||||
fun ListBottomBlankItem() {
|
fun ListBottomBlankItem() {
|
||||||
Row(
|
Row(
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
package com.pushdeer.os.ui.compose.componment
|
package com.pushdeer.os.ui.compose.componment
|
||||||
|
|
||||||
|
import android.widget.ImageView
|
||||||
import androidx.compose.foundation.BorderStroke
|
import androidx.compose.foundation.BorderStroke
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.border
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.*
|
import androidx.compose.material.*
|
||||||
@ -17,15 +19,17 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
import com.pushdeer.os.R
|
import com.pushdeer.os.R
|
||||||
import com.pushdeer.os.data.api.data.response.PushKey
|
import com.pushdeer.os.data.api.data.response.PushKey
|
||||||
import com.pushdeer.os.holder.RequestHolder
|
import com.pushdeer.os.holder.RequestHolder
|
||||||
import com.pushdeer.os.ui.theme.MBlue
|
import com.pushdeer.os.ui.theme.MBlue
|
||||||
|
import com.wh.common.util.QRCodeGenerator
|
||||||
import com.wh.common.util.TimeUtils
|
import com.wh.common.util.TimeUtils
|
||||||
|
|
||||||
@ExperimentalMaterialApi
|
@ExperimentalMaterialApi
|
||||||
@Composable
|
@Composable
|
||||||
fun KeyItem(key: PushKey,requestHolder: RequestHolder) {
|
fun KeyItem(key: PushKey, requestHolder: RequestHolder) {
|
||||||
var name by remember {
|
var name by remember {
|
||||||
mutableStateOf(key.name)
|
mutableStateOf(key.name)
|
||||||
}
|
}
|
||||||
@ -52,7 +56,7 @@ fun KeyItem(key: PushKey,requestHolder: RequestHolder) {
|
|||||||
},
|
},
|
||||||
onOk = {
|
onOk = {
|
||||||
key.name = name
|
key.name = name
|
||||||
requestHolder.keyRename(key)
|
requestHolder.key.rename(key)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}) {
|
}) {
|
||||||
@ -118,24 +122,36 @@ fun KeyItem(key: PushKey,requestHolder: RequestHolder) {
|
|||||||
color = Color.Gray,
|
color = Color.Gray,
|
||||||
shape = RoundedCornerShape(4.dp)
|
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)
|
.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(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
horizontalArrangement = Arrangement.SpaceBetween
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
) {
|
) {
|
||||||
OutlinedButton(
|
OutlinedButton(
|
||||||
onClick = { requestHolder.keyRegen(key.id) },
|
onClick = { requestHolder.key.regen(key.id) },
|
||||||
colors = ButtonDefaults.outlinedButtonColors(
|
colors = ButtonDefaults.outlinedButtonColors(
|
||||||
backgroundColor = Color.Transparent,
|
backgroundColor = Color.Transparent,
|
||||||
contentColor = MaterialTheme.colors.MBlue
|
contentColor = MaterialTheme.colors.MBlue
|
||||||
@ -147,7 +163,7 @@ fun KeyItem(key: PushKey,requestHolder: RequestHolder) {
|
|||||||
}
|
}
|
||||||
Button(
|
Button(
|
||||||
onClick = {
|
onClick = {
|
||||||
requestHolder.copyPlainString(key.key)
|
requestHolder.clip.copyPushKey(key.key)
|
||||||
},
|
},
|
||||||
colors = ButtonDefaults.buttonColors(
|
colors = ButtonDefaults.buttonColors(
|
||||||
backgroundColor = MaterialTheme.colors.MBlue,
|
backgroundColor = MaterialTheme.colors.MBlue,
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package com.pushdeer.os.ui.compose.componment
|
package com.pushdeer.os.ui.compose.componment
|
||||||
|
|
||||||
|
import android.widget.ImageView
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.Card
|
import androidx.compose.material.Card
|
||||||
@ -12,12 +14,12 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.layout.ContentScale
|
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.compose.ui.viewinterop.AndroidView
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
|
import coil.load
|
||||||
import com.pushdeer.os.R
|
import com.pushdeer.os.R
|
||||||
import com.pushdeer.os.data.database.entity.MessageEntity
|
import com.pushdeer.os.data.database.entity.MessageEntity
|
||||||
import com.pushdeer.os.holder.RequestHolder
|
import com.pushdeer.os.holder.RequestHolder
|
||||||
@ -27,11 +29,14 @@ import com.pushdeer.os.values.ConstValues
|
|||||||
|
|
||||||
@ExperimentalMaterialApi
|
@ExperimentalMaterialApi
|
||||||
@Composable
|
@Composable
|
||||||
fun PlainTextMessageItem(message: MessageEntity) {
|
fun PlainTextMessageItem(message: MessageEntity,requestHolder: RequestHolder) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.clip(RoundedCornerShape(4.dp))
|
.clip(RoundedCornerShape(4.dp))
|
||||||
|
.clickable {
|
||||||
|
requestHolder.clip.copyMessagePlainText(message.text)
|
||||||
|
}
|
||||||
.background(color = MaterialTheme.colors.surface)
|
.background(color = MaterialTheme.colors.surface)
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@ -47,7 +52,7 @@ fun PlainTextMessageItem(message: MessageEntity) {
|
|||||||
modifier = Modifier.size(40.dp)
|
modifier = Modifier.size(40.dp)
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = "${message.text}·${
|
text = "${message.pushkey_name}·${
|
||||||
CurrentTimeUtil.resolveUTCTimeAndNow(
|
CurrentTimeUtil.resolveUTCTimeAndNow(
|
||||||
message.created_at,
|
message.created_at,
|
||||||
System.currentTimeMillis()
|
System.currentTimeMillis()
|
||||||
@ -56,9 +61,9 @@ fun PlainTextMessageItem(message: MessageEntity) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
CardItemWithContent() {
|
CardItemWithContent {
|
||||||
Text(
|
Text(
|
||||||
text = message.desp,
|
text = message.text,
|
||||||
overflow = TextOverflow.Visible,
|
overflow = TextOverflow.Visible,
|
||||||
lineHeight = 24.sp,
|
lineHeight = 24.sp,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -71,12 +76,15 @@ fun PlainTextMessageItem(message: MessageEntity) {
|
|||||||
|
|
||||||
@ExperimentalMaterialApi
|
@ExperimentalMaterialApi
|
||||||
@Composable
|
@Composable
|
||||||
fun ImageMessageItem(message: MessageEntity) {
|
fun ImageMessageItem(message: MessageEntity, requestHolder: RequestHolder) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.clip(RoundedCornerShape(4.dp))
|
.clip(RoundedCornerShape(4.dp))
|
||||||
.background (color = MaterialTheme.colors.surface)
|
.clickable {
|
||||||
|
requestHolder.clip.copyMessagePlainText(message.text)
|
||||||
|
}
|
||||||
|
.background(color = MaterialTheme.colors.surface)
|
||||||
) {
|
) {
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
@ -92,7 +100,7 @@ fun ImageMessageItem(message: MessageEntity) {
|
|||||||
modifier = Modifier.size(40.dp)
|
modifier = Modifier.size(40.dp)
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = "${message.text}·${
|
text = "${message.pushkey_name}·${
|
||||||
CurrentTimeUtil.resolveUTCTimeAndNow(
|
CurrentTimeUtil.resolveUTCTimeAndNow(
|
||||||
message.created_at,
|
message.created_at,
|
||||||
System.currentTimeMillis()
|
System.currentTimeMillis()
|
||||||
@ -100,12 +108,13 @@ fun ImageMessageItem(message: MessageEntity) {
|
|||||||
}"
|
}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Card(modifier = Modifier.fillMaxWidth(), onClick = {}) {
|
Card(modifier = Modifier.fillMaxWidth()) {
|
||||||
Image(
|
AndroidView(factory = {
|
||||||
painter = painterResource(id = R.drawable.logo_com_x2),
|
ImageView(it).apply {
|
||||||
contentDescription = "",
|
scaleType = ImageView.ScaleType.FIT_CENTER
|
||||||
contentScale = ContentScale.FillWidth
|
load(message.text, requestHolder.coilImageLoader)
|
||||||
)
|
}
|
||||||
|
}, modifier = Modifier.fillMaxWidth())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -117,6 +126,9 @@ fun MarkdownMessageItem(message: MessageEntity, requestHolder: RequestHolder) {
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.clip(RoundedCornerShape(4.dp))
|
.clip(RoundedCornerShape(4.dp))
|
||||||
|
.clickable {
|
||||||
|
requestHolder.clip.copyMessagePlainText(message.text)
|
||||||
|
}
|
||||||
.background(color = MaterialTheme.colors.surface)
|
.background(color = MaterialTheme.colors.surface)
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@ -163,6 +175,13 @@ fun MarkdownMessageItem(message: MessageEntity, requestHolder: RequestHolder) {
|
|||||||
|
|
||||||
}, modifier = Modifier
|
}, modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
|
// .pointerInput(Unit) {
|
||||||
|
// this.detectTapGestures(
|
||||||
|
// onLongPress = {
|
||||||
|
// Log.d("WH_", "MarkdownMessageItem: ")
|
||||||
|
// }
|
||||||
|
// )
|
||||||
|
// }
|
||||||
.padding(16.dp)
|
.padding(16.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ fun LoginPage(requestHolder: RequestHolder) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is SignInWithAppleResult.Failure -> {
|
is SignInWithAppleResult.Failure -> {
|
||||||
requestHolder.alert.alert("Warning", {
|
requestHolder.alert.alert("Warning Apple Id Login Failed", {
|
||||||
result.error.message
|
result.error.message
|
||||||
}, onOk = {})
|
}, onOk = {})
|
||||||
Log.d(
|
Log.d(
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package com.pushdeer.os.ui.compose.page.main
|
package com.pushdeer.os.ui.compose.page.main
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
@ -41,7 +40,7 @@ fun DeviceListPage(requestHolder: RequestHolder) {
|
|||||||
onOk = {})
|
onOk = {})
|
||||||
// device regid got failed
|
// device regid got failed
|
||||||
} else {
|
} else {
|
||||||
requestHolder.deviceReg(
|
requestHolder.device.deviceReg(
|
||||||
deviceInfo = DeviceInfo().apply {
|
deviceInfo = DeviceInfo().apply {
|
||||||
name = SystemUtil.getDeviceModel()
|
name = SystemUtil.getDeviceModel()
|
||||||
device_id = requestHolder.settingStore.thisDeviceId
|
device_id = requestHolder.settingStore.thisDeviceId
|
||||||
@ -72,7 +71,7 @@ fun DeviceListPage(requestHolder: RequestHolder) {
|
|||||||
mutableStateOf(deviceInfo.name)
|
mutableStateOf(deviceInfo.name)
|
||||||
}
|
}
|
||||||
SwipeToDismissItem(
|
SwipeToDismissItem(
|
||||||
onAction = { requestHolder.deviceRemove(deviceInfo) }
|
onAction = { requestHolder.device.deviceRemove(deviceInfo) }
|
||||||
) {
|
) {
|
||||||
CardItemSingleLineWithIcon(
|
CardItemSingleLineWithIcon(
|
||||||
onClick = {
|
onClick = {
|
||||||
@ -99,7 +98,7 @@ fun DeviceListPage(requestHolder: RequestHolder) {
|
|||||||
},
|
},
|
||||||
onOk = {
|
onOk = {
|
||||||
deviceInfo.name = name
|
deviceInfo.name = name
|
||||||
requestHolder.deviceRename(deviceInfo)
|
requestHolder.device.deviceRename(deviceInfo)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@ -110,7 +109,7 @@ fun DeviceListPage(requestHolder: RequestHolder) {
|
|||||||
)
|
)
|
||||||
}) " else deviceInfo.name
|
}) " else deviceInfo.name
|
||||||
)
|
)
|
||||||
Log.d("WH_", "DeviceListPage: $deviceInfo")
|
// Log.d("WH_", "DeviceListPage: $deviceInfo")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
|
@ -25,7 +25,7 @@ import com.pushdeer.os.ui.navigation.Page
|
|||||||
fun KeyListPage(requestHolder: RequestHolder) {
|
fun KeyListPage(requestHolder: RequestHolder) {
|
||||||
MainPageFrame(
|
MainPageFrame(
|
||||||
titleStringId = Page.Keys.labelStringId,
|
titleStringId = Page.Keys.labelStringId,
|
||||||
onSideIconClick = { requestHolder.keyGen() }
|
onSideIconClick = { requestHolder.key.gen() }
|
||||||
) {
|
) {
|
||||||
if(requestHolder.pushDeerViewModel.keyList.isEmpty()){
|
if(requestHolder.pushDeerViewModel.keyList.isEmpty()){
|
||||||
Column(
|
Column(
|
||||||
@ -42,7 +42,7 @@ fun KeyListPage(requestHolder: RequestHolder) {
|
|||||||
items(
|
items(
|
||||||
requestHolder.pushDeerViewModel.keyList,
|
requestHolder.pushDeerViewModel.keyList,
|
||||||
key = { item: PushKey -> item.id }) { pushKey: PushKey ->
|
key = { item: PushKey -> item.id }) { pushKey: PushKey ->
|
||||||
SwipeToDismissItem(onAction = { requestHolder.keyRemove(pushKey) }
|
SwipeToDismissItem(onAction = { requestHolder.key.remove(pushKey) }
|
||||||
) {
|
) {
|
||||||
KeyItem(key = pushKey, requestHolder = requestHolder)
|
KeyItem(key = pushKey, requestHolder = requestHolder)
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ fun MainPage(requestHolder: RequestHolder) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var titleStringId by remember {
|
var titleStringId by remember {
|
||||||
mutableStateOf(Page.Devices.labelStringId)
|
mutableStateOf(Page.Messages.labelStringId)
|
||||||
}
|
}
|
||||||
val navController = rememberNavController()
|
val navController = rememberNavController()
|
||||||
Scaffold(
|
Scaffold(
|
||||||
@ -98,7 +98,7 @@ fun MainPage(requestHolder: RequestHolder) {
|
|||||||
)
|
)
|
||||||
NavHost(
|
NavHost(
|
||||||
navController = navController,
|
navController = navController,
|
||||||
startDestination = Page.Devices.route,
|
startDestination = Page.Messages.route,
|
||||||
) {
|
) {
|
||||||
composable(Page.Devices.route) {
|
composable(Page.Devices.route) {
|
||||||
DeviceListPage(requestHolder = requestHolder)
|
DeviceListPage(requestHolder = requestHolder)
|
||||||
|
@ -73,7 +73,7 @@ fun MessageListPage(requestHolder: RequestHolder) {
|
|||||||
)
|
)
|
||||||
Button(
|
Button(
|
||||||
onClick = {
|
onClick = {
|
||||||
requestHolder.messagePushTest(s)
|
requestHolder.message.messagePushTest(s)
|
||||||
},
|
},
|
||||||
colors = ButtonDefaults.buttonColors(
|
colors = ButtonDefaults.buttonColors(
|
||||||
backgroundColor = MaterialTheme.colors.MBlue,
|
backgroundColor = MaterialTheme.colors.MBlue,
|
||||||
@ -90,7 +90,7 @@ fun MessageListPage(requestHolder: RequestHolder) {
|
|||||||
key = { item: MessageEntity -> item.id }) { message: MessageEntity ->
|
key = { item: MessageEntity -> item.id }) { message: MessageEntity ->
|
||||||
SwipeToDismissItem(
|
SwipeToDismissItem(
|
||||||
onAction = {
|
onAction = {
|
||||||
requestHolder.messageRemove(message.toMessage(), onDone = {
|
requestHolder.message.messageRemove(message.toMessage(), onDone = {
|
||||||
requestHolder.messageViewModel.delete(message)
|
requestHolder.messageViewModel.delete(message)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@ -98,8 +98,8 @@ fun MessageListPage(requestHolder: RequestHolder) {
|
|||||||
) {
|
) {
|
||||||
when (message.type) {
|
when (message.type) {
|
||||||
"markdown" -> MarkdownMessageItem(message, requestHolder)
|
"markdown" -> MarkdownMessageItem(message, requestHolder)
|
||||||
"text" -> PlainTextMessageItem(message)
|
"text" -> PlainTextMessageItem(message, requestHolder)
|
||||||
"image" -> ImageMessageItem(message)
|
"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} !",
|
text = "${stringResource(id = R.string.main_setting_user_hi)} ${requestHolder.pushDeerViewModel.userInfo.name} !",
|
||||||
buttonString = stringResource(id = R.string.main_setting_user_logout)
|
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 = ""
|
requestHolder.settingStore.userToken = ""
|
||||||
// logout 操作:
|
requestHolder.globalNavController.navigate("login") {
|
||||||
// 从服务器删除本设备
|
requestHolder.globalNavController.popBackStack()
|
||||||
// 删除保存的 token
|
}
|
||||||
|
requestHolder.alert.alert(
|
||||||
|
"提示",
|
||||||
|
"由于厂商推送设备服务限制,暂时不支持更换为自建 PushDeer 服务器,但仅更换登陆账号并不会影响您的使用",
|
||||||
|
{}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// item {
|
// 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"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
<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" />
|
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||||
</adaptive-icon>
|
</adaptive-icon>
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
<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" />
|
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||||
</adaptive-icon>
|
</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.squareup.okhttp3:okhttp:4.9.2")
|
||||||
implementation 'com.google.code.gson:gson:2.8.9'
|
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"/>
|
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</manifest>
|
</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"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.wh.sbw.compose">
|
package="com.wh.sbw.compose">
|
||||||
|
|
||||||
|
|
||||||
</manifest>
|
</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 ':app'
|
||||||
include ':common'
|
include ':common'
|
||||||
include ':compose'
|
include ':compose'
|
||||||
|
include ':pushdeercommon'
|
||||||
|