Merge branch 'main' of https://github.com/easychen/pushdeer into main

This commit is contained in:
EasyChen 2022-01-21 13:05:49 +08:00
commit 93024fd028
35 changed files with 629 additions and 318 deletions

View File

@ -13,6 +13,7 @@
<entry key="../../../../layout/compose-model-1641659551303.xml" value="2.0" /> <entry key="../../../../layout/compose-model-1641659551303.xml" value="2.0" />
<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="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" />
</map> </map>

View File

@ -7,11 +7,12 @@
* MiPush状态已调通、已接入 * MiPush状态已调通、已接入
* miui 12.5.6 正常 * miui 12.5.6 正常
* 原生、类原生 可成功注册,无法收到推送,可能和地区识别有关,待解决 * 原生、类原生 可成功注册,无法收到推送,可能和地区识别有关,待解决
* miui下处于"几乎可用"的状态,已接入 appleId
### TODO ### TODO
* ~~调通 MiPush~~ * ~~调通 MiPush~~
* 接入 MiPush * ~~接入 MiPush~~
* 完善 log ~~采集~~ 回传机制,便于调试 * 完善 log ~~采集~~ 回传机制,便于调试
* 测试不同厂商设备上的通知推送效果 * 测试不同厂商设备上的通知推送效果
* ~~接入 PushDeer~~ * ~~接入 PushDeer~~
@ -21,6 +22,11 @@
* ~~增加侧滑手势相关动作~~ * ~~增加侧滑手势相关动作~~
* 增加各种操作前的二次确认弹窗,包括自动登陆 * 增加各种操作前的二次确认弹窗,包括自动登陆
* 增加非Miui设备的权限获取 * 增加非Miui设备的权限获取
* 增加手动修改服务器地址/退出登陆的逻辑(并放置到登陆界面)
* 增加登陆过程中的图形提示
* 增加对PushKey重命名的逻辑
* 增加对设备重命名的逻辑
* 增加长按复制消息内容的逻辑
### 日志 ### 日志
@ -88,6 +94,19 @@
* 调整项目文件结构 * 调整项目文件结构
* 将数据库用作message列表的直接数据来源 * 将数据库用作message列表的直接数据来源
* 2022-01-20
* 修改 /device/reg post参数增加 type=android
* 集成 SignIn With Apple
* 调整设备列表加号的显示和操作逻辑
* 将自动注册设备修改为手动点击加号注册设备
* 当前app几乎处于可以使用的状态
* 2022-01-21
* 修改登陆界面ui
* 增加key/device的重命名逻辑
* 适配英语和中文
### 感谢 ### 感谢
https://github.com/taoweiji/MixPush https://github.com/taoweiji/MixPush

View File

@ -9,7 +9,7 @@ android {
defaultConfig { defaultConfig {
applicationId "com.pushdeer.os" applicationId "com.pushdeer.os"
minSdk 21 minSdk 22
targetSdk 31 targetSdk 31
versionCode 1 versionCode 1
versionName "1.0" versionName "1.0"
@ -106,6 +106,8 @@ dependencies {
implementation "io.noties.markwon:html:$markwon_version" implementation "io.noties.markwon:html:$markwon_version"
implementation "io.coil-kt:coil:1.4.0" implementation "io.coil-kt:coil:1.4.0"
implementation 'com.github.vishalkumarsinghvi:sign-in-with-apple-button-android:0.6'
// implementation 'com.github.bumptech.glide:glide:4.12.0' // implementation 'com.github.bumptech.glide:glide:4.12.0'
// annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0' // annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
} }

View File

@ -0,0 +1,20 @@
{
"version": 3,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "com.pushdeer.os",
"variantName": "debug",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 1,
"versionName": "1.0",
"outputFile": "app-debug.apk"
}
],
"elementType": "File"
}

Binary file not shown.

View File

@ -24,7 +24,7 @@ class App : Application() {
val repositoryKeeper by lazy { RepositoryKeeper(database) } val repositoryKeeper by lazy { RepositoryKeeper(database) }
val pushDeerService by lazy { val pushDeerService by lazy {
Retrofit.Builder() Retrofit.Builder()
.baseUrl("http://0.0.0.0:8800") .baseUrl(PushDeerApi.baseUrl)
.addConverterFactory(ScalarsConverterFactory.create()) .addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create())
.build() .build()
@ -45,7 +45,7 @@ class App : Application() {
MiPushClient.registerPush(this, AppKeys.MiPush_Id, AppKeys.MiPush_Key) MiPushClient.registerPush(this, AppKeys.MiPush_Id, AppKeys.MiPush_Key)
} }
//打开Log //打开Log
val newLogger: LoggerInterface = object : LoggerInterface { Logger.setLogger(this, object : LoggerInterface {
override fun setTag(tag: String) { override fun setTag(tag: String) {
// ignore // ignore
} }
@ -57,8 +57,7 @@ class App : Application() {
override fun log(content: String) { override fun log(content: String) {
Log.d(TAG, content) Log.d(TAG, content)
} }
} })
Logger.setLogger(this, newLogger)
} }
private fun shouldInit(): Boolean { private fun shouldInit(): Boolean {

View File

@ -11,6 +11,7 @@ import androidx.activity.compose.setContent
import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.MaterialTheme import androidx.compose.material.MaterialTheme
@ -19,6 +20,7 @@ import androidx.compose.runtime.*
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.fragment.app.FragmentManager
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
@ -28,10 +30,10 @@ 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.activity.QrScanActivity
import com.pushdeer.os.data.api.data.request.DeviceInfo
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.page.LogDaoPage import com.pushdeer.os.ui.compose.componment.MyAlertDialog
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
@ -49,7 +51,7 @@ import kotlinx.coroutines.launch
import java.util.* import java.util.*
class MainActivity : ComponentActivity(), RequestHolder { class MainActivity : AppCompatActivity(), RequestHolder {
private val viewModelFactory by lazy { (application as App).viewModelFactory } private val viewModelFactory by lazy { (application as App).viewModelFactory }
private val repositoryKeeper by lazy { (application as App).repositoryKeeper } private val repositoryKeeper by lazy { (application as App).repositoryKeeper }
@ -59,6 +61,8 @@ class MainActivity : ComponentActivity(), RequestHolder {
override val logDogViewModel: LogDogViewModel by viewModels { viewModelFactory } override val logDogViewModel: LogDogViewModel by viewModels { viewModelFactory }
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 resource: Resources by lazy { this.resource }
override val coilImageLoader: ImageLoader by lazy { override val coilImageLoader: ImageLoader by lazy {
ImageLoader.Builder(this) ImageLoader.Builder(this)
@ -69,6 +73,7 @@ class MainActivity : ComponentActivity(), RequestHolder {
} }
.build() .build()
} }
override val alert: RequestHolder.AlertRequest by lazy { object : RequestHolder.AlertRequest(resources) {} }
override val markdown: Markwon by lazy { override val markdown: Markwon by lazy {
Markwon.builder(this) Markwon.builder(this)
@ -106,40 +111,22 @@ class MainActivity : ComponentActivity(), RequestHolder {
val useDarkIcons = MaterialTheme.colors.isLight val useDarkIcons = MaterialTheme.colors.isLight
val systemUiController = rememberSystemUiController() val systemUiController = rememberSystemUiController()
when { when {
SystemUtil.isMiui() -> { SystemUtil.isMiui() -> systemUiController.setStatusBarColor(Color.Transparent, useDarkIcons)
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
coroutineScope.launch {
if (pushDeerViewModel.shouldRegDevice()) {
pushDeerViewModel.deviceReg(DeviceInfo().apply {
this.name = SystemUtil.getDeviceModel()
this.device_id = it
this.is_clip = 0
})
}
}
} }
SideEffect { SideEffect {
coroutineScope.launch { coroutineScope.launch {
pushDeerViewModel.login().also { pushDeerViewModel.login(onReturn = {
pushDeerViewModel.userInfo()
pushDeerViewModel.keyList()
pushDeerViewModel.deviceList()
pushDeerViewModel.messageList()
globalNavController.navigate("main") { globalNavController.navigate("main") {
globalNavController.popBackStack() globalNavController.popBackStack()
} }
} })
} }
} }
@ -155,13 +142,14 @@ class MainActivity : ComponentActivity(), RequestHolder {
LoginPage(requestHolder = this@MainActivity) LoginPage(requestHolder = this@MainActivity)
} }
composable("logdog") { composable("logdog") {
LogDaoPage(requestHolder = this@MainActivity) LogDogPage(requestHolder = this@MainActivity)
} }
composable("main") { composable("main") {
MainPage(requestHolder = this@MainActivity) MainPage(requestHolder = this@MainActivity)
} }
} }
} }
MyAlertDialog(alertRequest = alert)
} }
} }
} }

View File

@ -1,11 +1,22 @@
package com.pushdeer.os.data.api package com.pushdeer.os.data.api
import com.pushdeer.os.data.api.data.response.* import com.pushdeer.os.data.api.data.response.*
import retrofit2.http.* import retrofit2.http.Field
import retrofit2.http.FieldMap
import retrofit2.http.FormUrlEncoded
import retrofit2.http.POST
interface PushDeerApi { interface PushDeerApi {
@GET("/login/fake") companion object {
suspend fun fakeLogin(): ReturnData<TokenOnly> val baseUrl = "https://api2.pushdeer.com"
}
@FormUrlEncoded
@POST("/login/idtoken")
suspend fun loginIdToken(@Field("idToken") idToken: String): ReturnData<TokenOnly>
// @GET("/login/fake")
// suspend fun fakeLogin(): ReturnData<TokenOnly>
@FormUrlEncoded @FormUrlEncoded
@POST("/user/info") @POST("/user/info")
@ -21,7 +32,15 @@ interface PushDeerApi {
@FormUrlEncoded @FormUrlEncoded
@POST("/device/remove") @POST("/device/remove")
suspend fun deviceRemove(@Field("token") token: String,@Field("id") id:Int): String 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 @FormUrlEncoded
@POST("/key/gen") @POST("/key/gen")
@ -39,6 +58,14 @@ interface PushDeerApi {
@POST("/key/remove") @POST("/key/remove")
suspend fun keyRemove(@FieldMap data: Map<String, String>): String 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
@FormUrlEncoded @FormUrlEncoded
@POST("/message/push") @POST("/message/push")
suspend fun messagePush(@FieldMap data: Map<String, String>): String suspend fun messagePush(@FieldMap data: Map<String, String>): String
@ -49,5 +76,5 @@ interface PushDeerApi {
@FormUrlEncoded @FormUrlEncoded
@POST("/message/remove") @POST("/message/remove")
suspend fun messageRemove(@Field("token")token:String,@Field("id")id:Int): String suspend fun messageRemove(@Field("token") token: String, @Field("id") id: Int): String
} }

View File

@ -13,7 +13,8 @@ class DeviceInfo {
"token" to token, "token" to token,
"name" to name, "name" to name,
"device_id" to device_id, "device_id" to device_id,
"is_clip" to is_clip.toString() "is_clip" to is_clip.toString(),
"type" to "android"
) )
} }

View File

@ -1,13 +0,0 @@
package com.pushdeer.os.data.api.data.response
class DeviceRemove {
var token: String = ""
var id = ""
fun toMap():Map<String,String> {
return mapOf(
"token" to token,
"id" to id
)
}
}

View File

@ -10,6 +10,7 @@ class Message : MessageEntity() {
this.text = this@Message.text this.text = this@Message.text
this.desp = this@Message.desp this.desp = this@Message.desp
this.type = this@Message.type this.type = this@Message.type
this.pushkey_name = this@Message.pushkey_name
this.created_at = this@Message.created_at this.created_at = this@Message.created_at
} }
} }

View File

@ -13,6 +13,7 @@ public class MessageEntity {
public String text; public String text;
public String desp; public String desp;
public String type; public String type;
public String pushkey_name;
public String created_at; public String created_at;
@ -20,10 +21,11 @@ public class MessageEntity {
Message m = new Message(); Message m = new Message();
m.id = id; m.id = id;
m.uid = uid; m.uid = uid;
m.created_at = created_at;
m.desp = desp;
m.text = text; m.text = text;
m.desp = desp;
m.type = type; m.type = type;
m.pushkey_name = pushkey_name;
m.created_at = created_at;
return m; return m;
} }
} }

View File

@ -1,4 +0,0 @@
package com.pushdeer.os.holder
interface DataHolder {
}

View File

@ -3,11 +3,18 @@ package com.pushdeer.os.holder
import android.content.ClipData import android.content.ClipData
import android.content.ClipboardManager import android.content.ClipboardManager
import android.content.Intent import android.content.Intent
import android.util.Log import android.content.res.Resources
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.ActivityResultLauncher
import androidx.annotation.StringRes
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
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.activity.QrScanActivity 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
@ -26,7 +33,7 @@ interface RequestHolder {
val uiViewModel: UiViewModel val uiViewModel: UiViewModel
val pushDeerViewModel: PushDeerViewModel val pushDeerViewModel: PushDeerViewModel
val logDogViewModel: LogDogViewModel val logDogViewModel: LogDogViewModel
val messageViewModel:MessageViewModel val messageViewModel: MessageViewModel
val settingStore: SettingStore val settingStore: SettingStore
val globalNavController: NavHostController val globalNavController: NavHostController
val coroutineScope: CoroutineScope val coroutineScope: CoroutineScope
@ -35,6 +42,12 @@ interface RequestHolder {
val activityOpener: ActivityResultLauncher<Intent> val activityOpener: ActivityResultLauncher<Intent>
val coilImageLoader: ImageLoader val coilImageLoader: ImageLoader
// val resource:Resources
val fragmentManager: FragmentManager
val alert: AlertRequest
val clipboardManager: ClipboardManager val clipboardManager: ClipboardManager
fun copyPlainString(str: String) { fun copyPlainString(str: String) {
@ -64,7 +77,17 @@ interface RequestHolder {
} }
} }
fun deviceReg(deviceInfo: DeviceInfo){ fun keyRename(pushKey: PushKey){
coroutineScope.launch {
pushDeerViewModel.keyRename(pushKey){
coroutineScope.launch {
pushDeerViewModel.keyList()
}
}
}
}
fun deviceReg(deviceInfo: DeviceInfo) {
coroutineScope.launch { coroutineScope.launch {
pushDeerViewModel.deviceReg(deviceInfo) pushDeerViewModel.deviceReg(deviceInfo)
} }
@ -77,24 +100,38 @@ interface RequestHolder {
} }
} }
fun deviceRename(deviceInfo: DeviceInfo) {
coroutineScope.launch {
pushDeerViewModel.deviceRename(deviceInfo) {
coroutineScope.launch {
pushDeerViewModel.deviceList()
}
}
}
}
fun messagePush(text: String, desp: String, type: String, pushkey: String) { fun messagePush(text: String, desp: String, type: String, pushkey: String) {
coroutineScope.launch { coroutineScope.launch {
pushDeerViewModel.messagePush(text, desp, type, pushkey) pushDeerViewModel.messagePush(text, desp, type, pushkey)
} }
} }
fun messagePushTest(desp: String) { fun messagePushTest(text: String) {
if (pushDeerViewModel.keyList.isNotEmpty()) { if (pushDeerViewModel.keyList.isNotEmpty()) {
messagePush("pushtest", desp, "markdown", pushDeerViewModel.keyList[0].key) messagePush(text, "pushtest", "markdown", pushDeerViewModel.keyList[0].key)
coroutineScope.launch { coroutineScope.launch {
delay(1000) delay(1000)
pushDeerViewModel.messageList() pushDeerViewModel.messageList()
} }
} else } else {
Log.d("WH_", "messagePushTest: keylist is empty") alert.alert(
R.string.global_alert_title_alert,
R.string.main_message_send_alert,
onOk = {})
}
} }
fun messageRemove(message: Message,onDone:()->Unit={}) { fun messageRemove(message: Message, onDone: () -> Unit = {}) {
coroutineScope.launch { coroutineScope.launch {
// pushDeerViewModel.messageList.remove(message) // pushDeerViewModel.messageList.remove(message)
pushDeerViewModel.messageRemove(message.id) pushDeerViewModel.messageRemove(message.id)
@ -112,4 +149,48 @@ interface RequestHolder {
logDogViewModel.clear() logDogViewModel.clear()
} }
} }
abstract class AlertRequest(private val resources: Resources) {
val show: MutableState<Boolean> = mutableStateOf(false)
var title: String = ""
var content: @Composable () -> Unit = {}
var onOKAction: () -> Unit = {}
var onCancelAction: () -> Unit = {}
fun alert(
title: String,
content: @Composable () -> Unit,
onOk: () -> Unit,
onCancel: () -> Unit = {}
) {
this.title = title
this.content = content
this.onOKAction = onOk
this.onCancelAction = onCancel
this.show.value = true
}
fun alert(title: String, content: String, onOk: () -> Unit, onCancel: () -> Unit = {}) {
alert(title, { Text(text = content) }, onOk, onCancel)
}
fun alert(
@StringRes title: Int,
@StringRes content: Int,
onOk: () -> Unit,
onCancel: () -> Unit = {}
) {
alert(resources.getString(title), resources.getString(content), onOk, onCancel)
}
fun alert(
@StringRes title: Int,
content: @Composable () -> Unit,
onOk: () -> Unit,
onCancel: () -> Unit={}
) {
alert(resources.getString(title), content, onOk, onCancel)
}
}
} }

View File

@ -33,7 +33,6 @@ class MessageReceiver : PushMessageReceiver() {
override fun onReceivePassThroughMessage(context: Context, message: MiPushMessage) { override fun onReceivePassThroughMessage(context: Context, message: MiPushMessage) {
init(context) init(context)
// Log.d("WH_", "onReceivePassThroughMessage: $message")
mMessage = message.content mMessage = message.content
if (!TextUtils.isEmpty(message.topic)) { if (!TextUtils.isEmpty(message.topic)) {
mTopic = message.topic mTopic = message.topic
@ -46,7 +45,6 @@ class MessageReceiver : PushMessageReceiver() {
override fun onNotificationMessageClicked(context: Context, message: MiPushMessage) { override fun onNotificationMessageClicked(context: Context, message: MiPushMessage) {
init(context) init(context)
// Log.d("WH_", "onNotificationMessageClicked: $message")
mMessage = message.content mMessage = message.content
if (!TextUtils.isEmpty(message.topic)) { if (!TextUtils.isEmpty(message.topic)) {
mTopic = message.topic mTopic = message.topic
@ -59,7 +57,6 @@ class MessageReceiver : PushMessageReceiver() {
override fun onNotificationMessageArrived(context: Context, message: MiPushMessage) { override fun onNotificationMessageArrived(context: Context, message: MiPushMessage) {
init(context) init(context)
// Log.d("WH_", "onNotificationMessageArrived: $message")
mMessage = message.content mMessage = message.content
if (!TextUtils.isEmpty(message.topic)) { if (!TextUtils.isEmpty(message.topic)) {
mTopic = message.topic mTopic = message.topic
@ -72,7 +69,6 @@ class MessageReceiver : PushMessageReceiver() {
override fun onCommandResult(context: Context, message: MiPushCommandMessage) { override fun onCommandResult(context: Context, message: MiPushCommandMessage) {
init(context) init(context)
// Log.d("WH_", "onCommandResult: $message")
val command = message.command val command = message.command
val arguments = message.commandArguments val arguments = message.commandArguments
val cmdArg1 = if (arguments != null && arguments.size > 0) arguments[0] else null val cmdArg1 = if (arguments != null && arguments.size > 0) arguments[0] else null
@ -108,7 +104,6 @@ class MessageReceiver : PushMessageReceiver() {
override fun onReceiveRegisterResult(context: Context, message: MiPushCommandMessage) { override fun onReceiveRegisterResult(context: Context, message: MiPushCommandMessage) {
init(context) init(context)
// Log.d("WH_", "onReceiveRegisterResult: $message")
val command = message.command val command = message.command
val arguments = message.commandArguments val arguments = message.commandArguments
val cmdArg1 = if (arguments != null && arguments.size > 0) arguments[0] else null val cmdArg1 = if (arguments != null && arguments.size > 0) arguments[0] else null

View File

@ -1,19 +0,0 @@
//package com.pushdeer.os.sss
//
//import android.content.Context
//import android.content.Intent
//import androidx.activity.result.contract.ActivityResultContract
//import com.pushdeer.os.activity.QrScanActivity
//
//class MyActivityResultContract : ActivityResultContract<String, String>() {
// override fun createIntent(context: Context, input: String): Intent {
// return QrScanActivity.forScanResultIntent(context)
// }
//
// override fun parseResult(resultCode: Int, intent: Intent?): String {
// intent?.let {
// return it.getStringExtra(QrScanActivity.DataKey).toString()
// }
// return ""
// }
//}

View File

@ -7,13 +7,13 @@ class SettingStore(context:Context) {
val store = Store.create(context,"setting") val store = Store.create(context,"setting")
var userToken by store.string("user-token","") var userToken by store.string("user-token","")
var deviceName by store.string("device-name","My Dear Deer") // var deviceName by store.string("device-name","My Dear Deer")
var useRecv by store.boolean("use-recv",false) // 启用接收 // var useRecv by store.boolean("use-recv",false) // 启用接收
var useSend by store.boolean("use-send",false) // var useSend by store.boolean("use-send",false)
var useSendNotification by store.boolean("use-send-notification",false) // var useSendNotification by store.boolean("use-send-notification",false)
var notificationPackages by store.stringSet("notification-packages", emptySet()) // var notificationPackages by store.stringSet("notification-packages", emptySet())
var useSendMissedCall by store.boolean("use-send=missed-call",false) // var useSendMissedCall by store.boolean("use-send=missed-call",false)
var useSendSMS by store.boolean("use-send-sms",false) // var useSendSMS by store.boolean("use-send-sms",false)
var showMessageSender by store.boolean("show-message-sender",true) var showMessageSender by store.boolean("show-message-sender",true)
var thisPushSdk by store.string("this-push-sdk","mi-push") var thisPushSdk by store.string("this-push-sdk","mi-push")

View File

@ -1,8 +0,0 @@
package com.pushdeer.os.typeExt
import androidx.lifecycle.LifecycleOwner
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch

View File

@ -8,11 +8,12 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.* import androidx.compose.material.*
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.DateRange import androidx.compose.material.icons.filled.DateRange
import androidx.compose.runtime.Composable import androidx.compose.runtime.*
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
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
@ -24,8 +25,37 @@ import com.wh.common.util.TimeUtils
@ExperimentalMaterialApi @ExperimentalMaterialApi
@Composable @Composable
fun KeyItem(key: PushKey, requestHolder: RequestHolder) { fun KeyItem(key: PushKey,requestHolder: RequestHolder) {
CardItemWithContent { var name by remember {
mutableStateOf(key.name)
}
CardItemWithContent(onClick = {
requestHolder.alert.alert(
title = R.string.main_key_alert_changekeyname,
content = {
Column {
TextField(
value = name,
onValueChange = { name = it },
shape = RoundedCornerShape(6.dp),
singleLine = true,
maxLines = 1,
label = { Text(text = stringResource(id = R.string.main_key_alert_keyname)) },
colors = TextFieldDefaults.textFieldColors(
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent,
errorIndicatorColor = Color.Transparent,
)
)
}
},
onOk = {
key.name = name
requestHolder.keyRename(key)
}
)
}) {
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@ -113,7 +143,7 @@ fun KeyItem(key: PushKey, requestHolder: RequestHolder) {
border = BorderStroke(1.dp, MaterialTheme.colors.MBlue), border = BorderStroke(1.dp, MaterialTheme.colors.MBlue),
shape = RoundedCornerShape(6.dp) shape = RoundedCornerShape(6.dp)
) { ) {
Text(text = "Reset") Text(text = stringResource(id = R.string.main_key_reset))
} }
Button( Button(
onClick = { onClick = {
@ -125,7 +155,7 @@ fun KeyItem(key: PushKey, requestHolder: RequestHolder) {
), ),
shape = RoundedCornerShape(6.dp) shape = RoundedCornerShape(6.dp)
) { ) {
Text(text = "Copy") Text(text = stringResource(id = R.string.main_key_copy))
} }
} }
} }

View File

@ -4,7 +4,10 @@ import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
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.Card
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable 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
@ -18,7 +21,6 @@ import androidx.compose.ui.viewinterop.AndroidView
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
import com.pushdeer.os.ui.theme.MBlue
import com.pushdeer.os.util.CurrentTimeUtil import com.pushdeer.os.util.CurrentTimeUtil
import com.pushdeer.os.values.ConstValues import com.pushdeer.os.values.ConstValues
@ -129,18 +131,18 @@ fun MarkdownMessageItem(message: MessageEntity, requestHolder: RequestHolder) {
contentDescription = "", contentDescription = "",
modifier = Modifier.size(40.dp) modifier = Modifier.size(40.dp)
) )
Icon( // Icon(
painter = painterResource(id = R.drawable.ic_markdown), // painter = painterResource(id = R.drawable.ic_markdown),
contentDescription = "", // contentDescription = "",
tint = MaterialTheme.colors.MBlue, // tint = MaterialTheme.colors.MBlue,
modifier = Modifier // modifier = Modifier
.size(20.dp) // .size(20.dp)
.align(alignment = Alignment.BottomCenter) // .align(alignment = Alignment.BottomCenter)
) // )
} }
Text( Text(
text = "${message.text}·${ text = "${message.pushkey_name}·${
CurrentTimeUtil.resolveUTCTimeAndNow( CurrentTimeUtil.resolveUTCTimeAndNow(
message.created_at, message.created_at,
System.currentTimeMillis() System.currentTimeMillis()
@ -155,7 +157,7 @@ fun MarkdownMessageItem(message: MessageEntity, requestHolder: RequestHolder) {
android.widget.TextView(ctx).apply { android.widget.TextView(ctx).apply {
this.post { this.post {
// requestHolder.markdown.configuration().theme(). // requestHolder.markdown.configuration().theme().
requestHolder.markdown.setMarkdown(this, message.desp) requestHolder.markdown.setMarkdown(this, message.text)
} }
} }

View File

@ -0,0 +1,38 @@
package com.pushdeer.os.ui.compose.componment
import androidx.compose.material.AlertDialog
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import com.pushdeer.os.R
import com.pushdeer.os.holder.RequestHolder
@Composable
fun MyAlertDialog(alertRequest: RequestHolder.AlertRequest) {
if (alertRequest.show.value) {
AlertDialog(
onDismissRequest = { alertRequest.show.value = false },
confirmButton = {
TextButton(onClick = {
alertRequest.onOKAction.invoke()
alertRequest.show.value = false
}) {
Text(text = stringResource(id = R.string.global_alert_ok))
}
},
dismissButton = {
TextButton(onClick = {
alertRequest.onCancelAction.invoke()
alertRequest.show.value = false
}) {
Text(text = stringResource(id = R.string.global_alert_cancel))
}
},
title = { Text(text = alertRequest.title) },
text = alertRequest.content
)
}
}

View File

@ -7,7 +7,6 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.* import androidx.compose.material.*
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Done
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
@ -20,13 +19,13 @@ import com.pushdeer.os.values.ConstValues
@ExperimentalMaterialApi @ExperimentalMaterialApi
@Composable @Composable
fun SwipeToDismissItem( fun SwipeToDismissItem(
onDismiss: () -> Unit, onAction: () -> Unit,
sidePadding: Boolean = false, sidePadding: Boolean = false,
content: @Composable RowScope.() -> Unit content: @Composable RowScope.() -> Unit
) { ) {
val dismissState = rememberDismissState() val dismissState = rememberDismissState()
if (dismissState.isDismissed(DismissDirection.EndToStart)) { if (dismissState.isDismissed(DismissDirection.EndToStart)) {
onDismiss() onAction()
} }
Column(modifier = Modifier Column(modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@ -34,7 +33,7 @@ fun SwipeToDismissItem(
SwipeToDismiss( SwipeToDismiss(
state = dismissState, state = dismissState,
background = { background = {
val direction = dismissState.dismissDirection ?: return@SwipeToDismiss // val direction = dismissState.dismissDirection ?: return@SwipeToDismiss
val color by animateColorAsState( val color by animateColorAsState(
when (dismissState.targetValue) { when (dismissState.targetValue) {
@ -44,15 +43,18 @@ fun SwipeToDismissItem(
} }
) )
val alignment = when (direction) { // val alignment = when (direction) {
DismissDirection.StartToEnd -> Alignment.CenterStart // DismissDirection.StartToEnd -> Alignment.CenterStart
DismissDirection.EndToStart -> Alignment.CenterEnd // DismissDirection.EndToStart -> Alignment.CenterEnd
} // }
//
// val icon = when (direction) {
// DismissDirection.StartToEnd -> Icons.Default.Done
// DismissDirection.EndToStart -> Icons.Default.Delete
// }
val icon = when (direction) { val alignment = Alignment.CenterEnd
DismissDirection.StartToEnd -> Icons.Default.Done val icon = Icons.Default.Delete
DismissDirection.EndToStart -> Icons.Default.Delete
}
Box( Box(
contentAlignment = alignment, contentAlignment = alignment,
@ -69,7 +71,7 @@ fun SwipeToDismissItem(
) )
} }
}, },
directions = setOf(DismissDirection.EndToStart, DismissDirection.EndToStart), directions = setOf(DismissDirection.EndToStart),
dismissThresholds = { direction -> dismissThresholds = { direction ->
FractionalThreshold(if (direction == DismissDirection.EndToStart) 0.45f else 0.57f) FractionalThreshold(if (direction == DismissDirection.EndToStart) 0.45f else 0.57f)
}, },

View File

@ -25,7 +25,7 @@ import com.pushdeer.os.ui.compose.page.main.MainPageFrame
@ExperimentalMaterialApi @ExperimentalMaterialApi
@Composable @Composable
fun LogDaoPage(requestHolder: RequestHolder) { fun LogDogPage(requestHolder: RequestHolder) {
MainPageFrame( MainPageFrame(
titleStringId = R.string.global_logdog, titleStringId = R.string.global_logdog,
sideIcon = Icons.Default.Delete, sideIcon = Icons.Default.Delete,

View File

@ -1,76 +1,82 @@
package com.pushdeer.os.ui.compose.page package com.pushdeer.os.ui.compose.page
import android.util.Log
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.border import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Card
import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Text
import androidx.compose.runtime.Composable 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.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import com.pushdeer.os.R import com.pushdeer.os.R
import com.pushdeer.os.holder.RequestHolder import com.pushdeer.os.holder.RequestHolder
import com.pushdeer.os.ui.theme.MainBlue import com.willowtreeapps.signinwithapplebutton.SignInWithAppleConfiguration
import com.pushdeer.os.ui.theme.MainGreen import com.willowtreeapps.signinwithapplebutton.SignInWithAppleResult
import com.willowtreeapps.signinwithapplebutton.view.SignInWithAppleButton
import kotlinx.coroutines.launch
@ExperimentalMaterialApi @ExperimentalMaterialApi
@Composable @Composable
fun LoginPage(requestHolder: RequestHolder) { fun LoginPage(requestHolder: RequestHolder) {
Column( Box(modifier = Modifier.fillMaxSize()) {
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally val configuration = SignInWithAppleConfiguration.Builder()
) { .clientId("com.pushdeer.site")
.redirectUri("https://api2.pushdeer.com/callback/apple")
.responseType(SignInWithAppleConfiguration.ResponseType.ALL)
.scope(SignInWithAppleConfiguration.Scope.EMAIL)
.build()
Image( Image(
painter = painterResource(R.drawable.logo_com_x2), painter = painterResource(R.drawable.logo_com_x2),
contentDescription = "big push deer logo" contentDescription = "big push deer logo",
)
Card(
onClick = { /*TODO*/ },
shape = RoundedCornerShape(4.dp),
modifier = Modifier modifier = Modifier
.padding(bottom = 16.dp) .clickable { requestHolder.globalNavController.navigate("logdog") }
.border( .align(Alignment.TopCenter)
width = 1.dp, .padding(top = 50.dp)
color = MainBlue, )
shape = RoundedCornerShape(4.dp) AndroidView(
) factory = {
) { SignInWithAppleButton(it).apply {
Text( setUpSignInWithAppleOnClick(
text = "Sign in with Apple", requestHolder.fragmentManager,
color = MainBlue, configuration
textAlign = TextAlign.Center, ) { result ->
modifier = Modifier when (result) {
.padding(vertical = 16.dp) is SignInWithAppleResult.Success -> {
.fillMaxWidth(0.6F) Log.d("WH_", "apple-id_token:${result.idToken}")
requestHolder.coroutineScope.launch {
) requestHolder.pushDeerViewModel.login(result.idToken) {
} requestHolder.globalNavController.navigate("main") {
Card( requestHolder.globalNavController.popBackStack()
onClick = {}, }
shape = RoundedCornerShape(4.dp), }
modifier = Modifier.border( }
width = 1.dp, }
color = MainGreen, is SignInWithAppleResult.Failure -> {
shape = RoundedCornerShape(4.dp) requestHolder.alert.alert("Warning", {
) result.error.message
) { }, onOk = {})
Text( Log.d(
text = "Sign in with WeChat", "WH_",
color = MainGreen, "Received error from Apple Sign In ${result.error.message}"
textAlign = TextAlign.Center, )
modifier = Modifier }
.padding(vertical = 16.dp) is SignInWithAppleResult.Cancel -> {
.fillMaxWidth(0.6F) Log.d("WH_", "User canceled Apple Sign In")
) }
} }
}
}
},
modifier = Modifier
.align(alignment = Alignment.BottomCenter)
.padding(bottom = 100.dp)
)
} }
} }

View File

@ -1,23 +1,25 @@
package com.pushdeer.os.ui.compose.page.main package com.pushdeer.os.ui.compose.page.main
import android.os.Build import android.util.Log
import android.text.TextUtils 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
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.Card import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Text import androidx.compose.material.Text
import androidx.compose.runtime.Composable import androidx.compose.material.TextField
import androidx.compose.material.TextFieldDefaults
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.pushdeer.os.R import com.pushdeer.os.R
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.UserInfo
import com.pushdeer.os.holder.RequestHolder import com.pushdeer.os.holder.RequestHolder
import com.pushdeer.os.ui.compose.componment.CardItemSingleLineWithIcon import com.pushdeer.os.ui.compose.componment.CardItemSingleLineWithIcon
import com.pushdeer.os.ui.compose.componment.ListBottomBlankItem import com.pushdeer.os.ui.compose.componment.ListBottomBlankItem
@ -32,78 +34,89 @@ fun DeviceListPage(requestHolder: RequestHolder) {
MainPageFrame( MainPageFrame(
titleStringId = Page.Devices.labelStringId, titleStringId = Page.Devices.labelStringId,
onSideIconClick = { onSideIconClick = {
requestHolder.deviceReg( if (requestHolder.settingStore.thisDeviceId == "") {
deviceInfo = DeviceInfo().apply { requestHolder.alert.alert(
name = System.currentTimeMillis().toString() title = R.string.global_alert_title_confirm,
device_id = "sdsdf" content = R.string.alert_device_register_failed_push_sdk,
is_clip = 0 onOk = {})
} // device regid got failed
) } else {
} requestHolder.deviceReg(
deviceInfo = DeviceInfo().apply {
name = SystemUtil.getDeviceModel()
device_id = requestHolder.settingStore.thisDeviceId
is_clip = 0
}
)
}
},
showSideIcon = requestHolder.pushDeerViewModel.shouldRegDevice()
) { ) {
val state = rememberLazyListState() if (requestHolder.pushDeerViewModel.deviceList.isEmpty()) {
LazyColumn(state = state) { Column(
items( modifier = Modifier.fillMaxSize(),
items = requestHolder.pushDeerViewModel.deviceList, horizontalAlignment = Alignment.CenterHorizontally,
key = { item: DeviceInfo -> item.id }) { deviceInfo: DeviceInfo -> verticalArrangement = Arrangement.Center
SwipeToDismissItem(onDismiss = { requestHolder.deviceRemove(deviceInfo) }) { ) {
CardItemSingleLineWithIcon( Text(
onClick = {}, text = stringResource(id = R.string.main_device_list_placeholder)
resId = R.drawable.ipad_landscape2x, )
text = if (deviceInfo.device_id == requestHolder.settingStore.thisDeviceId) "${deviceInfo.name} (this device)" else deviceInfo.name }
) } else {
val state = rememberLazyListState()
LazyColumn(state = state) {
items(
items = requestHolder.pushDeerViewModel.deviceList,
key = { item: DeviceInfo -> item.id }) { deviceInfo: DeviceInfo ->
var name by remember {
mutableStateOf(deviceInfo.name)
}
SwipeToDismissItem(
onAction = { requestHolder.deviceRemove(deviceInfo) }
) {
CardItemSingleLineWithIcon(
onClick = {
requestHolder.alert.alert(
title = R.string.main_device_alert_changedevicename,
content = {
Column {
// Text(text = "type:${deviceInfo.type}")
TextField(
value = name,
onValueChange = { name = it },
shape = RoundedCornerShape(6.dp),
singleLine = true,
maxLines = 1,
label = { Text(text = stringResource(id = R.string.main_device_alert_devicename)) },
colors = TextFieldDefaults.textFieldColors(
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent,
errorIndicatorColor = Color.Transparent,
)
)
}
},
onOk = {
deviceInfo.name = name
requestHolder.deviceRename(deviceInfo)
}
)
},
resId = R.drawable.ipad_landscape2x,
text = if (deviceInfo.device_id == requestHolder.settingStore.thisDeviceId) "${deviceInfo.name} (${
stringResource(
id = R.string.main_device_this_device
)
}) " else deviceInfo.name
)
Log.d("WH_", "DeviceListPage: $deviceInfo")
}
} }
} item {
item { ListBottomBlankItem()
ListBottomBlankItem()
}
}
}
}
@ExperimentalMaterialApi
@Composable
fun DeviceListPage(userInfo: UserInfo, token: String, regid: String) {
LazyColumn(
modifier = Modifier
.fillMaxSize()
.padding(horizontal = 8.dp)
.padding(top = 8.dp)
) {
item {
Card(elevation = 5.dp, onClick = {}, modifier = Modifier.fillMaxWidth()) {
Column(modifier = Modifier.padding(horizontal = 16.dp, vertical = 14.dp)) {
Text(text = "当前版本 Android ${SystemUtil.getSystemVersion()}")
Text(text = "本机品牌 ${SystemUtil.getDeviceBrand()}")
Text(text = "本机型号 ${SystemUtil.getDeviceModel()}")
Text(text = "产品名称 ${Build.PRODUCT}")
MiuiVersion()
} }
} }
} }
item {
Card(elevation = 5.dp, onClick = {}, modifier = Modifier.fillMaxWidth()) {
Column(modifier = Modifier.padding(horizontal = 16.dp, vertical = 14.dp)) {
Text(text = "id ${userInfo.id}")
Text(text = "name ${userInfo.name}")
Text(text = "email ${userInfo.email}")
Text(text = "app_id ${userInfo.app_id}")
Text(text = "wechat_id ${userInfo.wechat_id}")
Text(text = "created_at ${userInfo.created_at}")
Text(text = "updated_at ${userInfo.updated_at}")
Text(text = "level ${userInfo.level}")
Text(text = "token $token")
Text(text = "regid $regid")
}
}
}
}
}
@Composable
fun MiuiVersion() {
val v = SystemUtil.getMiuiVersion()
if (!TextUtils.isEmpty(v)) {
Text(text = "Miui 版本 ${v}")
} }
} }

View File

@ -1,11 +1,18 @@
package com.pushdeer.os.ui.compose.page.main package com.pushdeer.os.ui.compose.page.main
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
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.compose.componment.KeyItem import com.pushdeer.os.ui.compose.componment.KeyItem
@ -20,17 +27,29 @@ fun KeyListPage(requestHolder: RequestHolder) {
titleStringId = Page.Keys.labelStringId, titleStringId = Page.Keys.labelStringId,
onSideIconClick = { requestHolder.keyGen() } onSideIconClick = { requestHolder.keyGen() }
) { ) {
LazyColumn(modifier = Modifier.fillMaxWidth()) { if(requestHolder.pushDeerViewModel.keyList.isEmpty()){
items( Column(
requestHolder.pushDeerViewModel.keyList, modifier = Modifier.fillMaxSize(),
key = { item: PushKey -> item.id }) { pushKey: PushKey -> horizontalAlignment = Alignment.CenterHorizontally,
SwipeToDismissItem(onDismiss = { requestHolder.keyRemove(pushKey) } verticalArrangement = Arrangement.Center
) { ) {
KeyItem(key = pushKey, requestHolder = requestHolder) Text(
} text = stringResource(id = R.string.main_key_list_placeholder)
)
} }
item { }else{
ListBottomBlankItem() LazyColumn(modifier = Modifier.fillMaxWidth()) {
items(
requestHolder.pushDeerViewModel.keyList,
key = { item: PushKey -> item.id }) { pushKey: PushKey ->
SwipeToDismissItem(onAction = { requestHolder.keyRemove(pushKey) }
) {
KeyItem(key = pushKey, requestHolder = requestHolder)
}
}
item {
ListBottomBlankItem()
}
} }
} }
} }

View File

@ -26,12 +26,22 @@ import com.pushdeer.os.holder.RequestHolder
import com.pushdeer.os.ui.navigation.Page import com.pushdeer.os.ui.navigation.Page
import com.pushdeer.os.ui.navigation.pageList import com.pushdeer.os.ui.navigation.pageList
import com.pushdeer.os.ui.theme.mainBottomBtn import com.pushdeer.os.ui.theme.mainBottomBtn
import kotlinx.coroutines.launch
@ExperimentalAnimationApi @ExperimentalAnimationApi
@ExperimentalMaterialApi @ExperimentalMaterialApi
@Composable @Composable
fun MainPage(requestHolder: RequestHolder) { fun MainPage(requestHolder: RequestHolder) {
SideEffect {
requestHolder.coroutineScope.launch {
requestHolder.pushDeerViewModel.userInfo()
requestHolder.pushDeerViewModel.keyList()
requestHolder.pushDeerViewModel.deviceList()
requestHolder.pushDeerViewModel.messageList()
}
}
var titleStringId by remember { var titleStringId by remember {
mutableStateOf(Page.Devices.labelStringId) mutableStateOf(Page.Devices.labelStringId)
} }

View File

@ -14,7 +14,9 @@ import androidx.compose.material.icons.filled.KeyboardArrowUp
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
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
import com.pushdeer.os.ui.compose.componment.* import com.pushdeer.os.ui.compose.componment.*
@ -78,7 +80,7 @@ fun MessageListPage(requestHolder: RequestHolder) {
contentColor = Color.White contentColor = Color.White
), ),
) { ) {
Text(text = "Send") Text(text = stringResource(id = R.string.main_message_send))
} }
} }
} }
@ -87,15 +89,13 @@ fun MessageListPage(requestHolder: RequestHolder) {
items = messageList, items = messageList,
key = { item: MessageEntity -> item.id }) { message: MessageEntity -> key = { item: MessageEntity -> item.id }) { message: MessageEntity ->
SwipeToDismissItem( SwipeToDismissItem(
onDismiss = { onAction = {
requestHolder.messageRemove(message.toMessage(), onDone = { requestHolder.messageRemove(message.toMessage(), onDone = {
requestHolder.messageViewModel.delete(message) requestHolder.messageViewModel.delete(message)
}) })
}, },
// sidePadding = false
sidePadding = message.type != "image" sidePadding = message.type != "image"
) { ) {
// ImageMessageItem(message)
when (message.type) { when (message.type) {
"markdown" -> MarkdownMessageItem(message, requestHolder) "markdown" -> MarkdownMessageItem(message, requestHolder)
"text" -> PlainTextMessageItem(message) "text" -> PlainTextMessageItem(message)

View File

@ -1,13 +1,12 @@
package com.pushdeer.os.ui.compose.page.main package com.pushdeer.os.ui.compose.page.main
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import com.pushdeer.os.R
import com.pushdeer.os.holder.RequestHolder import com.pushdeer.os.holder.RequestHolder
import com.pushdeer.os.ui.compose.componment.SettingItem import com.pushdeer.os.ui.compose.componment.SettingItem
import com.pushdeer.os.ui.navigation.Page import com.pushdeer.os.ui.navigation.Page
@ -24,8 +23,8 @@ fun SettingPage(requestHolder: RequestHolder) {
) { ) {
item { item {
SettingItem( SettingItem(
text = "Hi ${requestHolder.pushDeerViewModel.userInfo.name} !", text = "${stringResource(id = R.string.main_setting_user_hi)} ${requestHolder.pushDeerViewModel.userInfo.name} !",
buttonString = "Logout" buttonString = stringResource(id = R.string.main_setting_user_logout)
) { ) {
requestHolder.settingStore.userToken = "" requestHolder.settingStore.userToken = ""
// logout 操作: // logout 操作:
@ -33,26 +32,26 @@ fun SettingPage(requestHolder: RequestHolder) {
// 删除保存的 token // 删除保存的 token
} }
} }
item { // item {
SettingItem( // SettingItem(
text = "Customize Server", // text = "Customize Server",
buttonString = "Scan QR" // buttonString = "Scan QR"
) { // ) {
requestHolder.startQrScanActivity() // requestHolder.startQrScanActivity()
} // }
} // }
item { // item {
SettingItem( // SettingItem(
text = "Do you like PushDeer ?", // text = "Do you like PushDeer ?",
buttonString = "Like" // buttonString = "Like"
) { // ) {
} // }
} // }
item { item {
SettingItem( SettingItem(
text = "LogDog", text = stringResource(id = R.string.main_setting_logdog),
buttonString = "Open" buttonString = stringResource(id = R.string.main_setting_logdog_open)
) { ) {
requestHolder.globalNavController.navigate("logdog") requestHolder.globalNavController.navigate("logdog")
} }
@ -61,12 +60,12 @@ fun SettingPage(requestHolder: RequestHolder) {
} }
} }
@Composable //@Composable
fun TogglePreferenceItem(label: String) { //fun TogglePreferenceItem(label: String) {
Row( // Row(
verticalAlignment = Alignment.CenterVertically, // verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxSize() // modifier = Modifier.fillMaxSize()
) { // ) {
Text(text = label) // Text(text = label)
} // }
} //}

View File

@ -19,7 +19,7 @@ import kotlinx.coroutines.withContext
class PushDeerViewModel( class PushDeerViewModel(
private val settingStore: SettingStore, private val settingStore: SettingStore,
private val logDogRepository: LogDogRepository, private val logDogRepository: LogDogRepository,
private val pushDeerService:PushDeerApi, private val pushDeerService: PushDeerApi,
private val messageRepository: MessageRepository private val messageRepository: MessageRepository
) : ViewModel() { ) : ViewModel() {
private val TAG = "WH_" private val TAG = "WH_"
@ -30,14 +30,18 @@ class PushDeerViewModel(
val keyList = mutableStateListOf<PushKey>() val keyList = mutableStateListOf<PushKey>()
// var messageList = mutableStateListOf<Message>() // var messageList = mutableStateListOf<Message>()
suspend fun login(onReturn: (String) -> Unit = {}) { suspend fun login(idToken: String = "", onReturn: (String) -> Unit = {}) {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
if (token == "") { if (token == "" && idToken != "") {
try { try {
pushDeerService.fakeLogin().let { pushDeerService.loginIdToken(idToken).let {
it.content?.let { tokenOnly -> it.content?.let { tokenOnly ->
settingStore.userToken = tokenOnly.token settingStore.userToken = tokenOnly.token
token = tokenOnly.token token = tokenOnly.token
Log.d(TAG, "login: $token")
withContext(Dispatchers.Main) {
onReturn.invoke(token)
}
} }
} }
} catch (e: Exception) { } catch (e: Exception) {
@ -45,18 +49,26 @@ class PushDeerViewModel(
logDogRepository.loge("login", "", e.toString()) logDogRepository.loge("login", "", e.toString())
return@withContext return@withContext
} }
logDogRepository.logi("login","normally","nothing happened") logDogRepository.logi("login", "normally", "nothing happened")
} else if (token == "" && idToken == "") {
return@withContext
} else if (token != "") {
withContext(Dispatchers.Main) {
onReturn.invoke(token)
}
} }
// Log.d(TAG, "login: token $token")
} }
} }
suspend fun userInfo(onReturn: (UserInfo) -> Unit = {}) { suspend fun userInfo(onOk: (UserInfo) -> Unit = {}, onFailed: () -> Unit = {}) {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
try { try {
pushDeerService.userInfo(token).let { pushDeerService.userInfo(token).let {
it.content?.let { ita -> it.content?.let { ita ->
userInfo = ita userInfo = ita
withContext(Dispatchers.Main) {
onOk(userInfo)
}
} }
} }
} catch (e: Exception) { } catch (e: Exception) {
@ -97,17 +109,17 @@ class PushDeerViewModel(
pushDeerService.deviceList(token).let { pushDeerService.deviceList(token).let {
it.content?.let { it.content?.let {
deviceList.clear() deviceList.clear()
deviceList.addAll(it.devices) deviceList.addAll(it.devices.reversed())
} }
} }
} catch (e: Exception) { } catch (e: Exception) {
Log.d(TAG, "deviceList: ${e.localizedMessage}") Log.d(TAG, "deviceList: ${e.localizedMessage}")
logDogRepository.loge("deviceList", "", e.toString())
} }
} }
} }
fun shouldRegDevice(): Boolean { fun shouldRegDevice(): Boolean {
// Log.d(TAG, "isDeviceReged: current device id ${settingStore.thisDeviceId}")
return deviceList.none { it.device_id == settingStore.thisDeviceId } return deviceList.none { it.device_id == settingStore.thisDeviceId }
} }
@ -120,6 +132,19 @@ class PushDeerViewModel(
} }
} catch (e: Exception) { } catch (e: Exception) {
Log.d(TAG, "deviceRemove: ${e.localizedMessage}") Log.d(TAG, "deviceRemove: ${e.localizedMessage}")
logDogRepository.loge("deviceRemove", "", e.toString())
}
}
}
suspend fun deviceRename(deviceInfo: DeviceInfo,onReturn: () -> Unit={}){
withContext(Dispatchers.IO){
try {
pushDeerService.deviceRename(token,deviceInfo.id,deviceInfo.name)
onReturn()
}catch (e:Exception){
Log.d(TAG, "deviceRename: ${e.localizedMessage}")
logDogRepository.loge("deviceRename", "", e.toString())
} }
} }
} }
@ -135,6 +160,7 @@ class PushDeerViewModel(
} }
} catch (e: Exception) { } catch (e: Exception) {
Log.d(TAG, "keyGen: ${e.localizedMessage}") Log.d(TAG, "keyGen: ${e.localizedMessage}")
logDogRepository.loge("keyGen", "", e.toString())
} }
} }
} }
@ -152,6 +178,23 @@ class PushDeerViewModel(
} }
} catch (e: Exception) { } catch (e: Exception) {
Log.d(TAG, "keyRegen: ${e.localizedMessage}") Log.d(TAG, "keyRegen: ${e.localizedMessage}")
logDogRepository.loge("keyRegen", "", e.toString())
}
}
}
suspend fun keyRename(key: PushKey,onReturn: () -> Unit={}){
withContext(Dispatchers.IO){
try {
pushDeerService.keyRename(
token,
key.id,
key.name
)
onReturn()
}catch (e: Exception) {
Log.d(TAG, "keyRename: ${e.localizedMessage}")
logDogRepository.loge("keyRename", "", e.toString())
} }
} }
} }
@ -167,6 +210,7 @@ class PushDeerViewModel(
} }
} catch (e: Exception) { } catch (e: Exception) {
Log.d(TAG, "keyList: ${e.localizedMessage}") Log.d(TAG, "keyList: ${e.localizedMessage}")
logDogRepository.loge("keyList", "", e.toString())
} }
} }
} }
@ -179,6 +223,7 @@ class PushDeerViewModel(
} }
} catch (e: Exception) { } catch (e: Exception) {
Log.d(TAG, "keyRemove: ${e.localizedMessage}") Log.d(TAG, "keyRemove: ${e.localizedMessage}")
logDogRepository.loge("keyRemove", "", e.toString())
} }
} }

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">PushDeer</string>
</resources>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">PushDeer</string>
<string name="main_device">设备</string>
<string name="main_key">密钥</string>
<string name="main_message">消息</string>
<string name="main_setting">设置</string>
<string name="global_logdog">LogDog-罗格狗</string>
<string name="main_key_reset">重置</string>
<string name="main_key_copy">复制</string>
<string name="main_setting_logdog_open">打开</string>
<string name="main_setting_user_hi">你好</string>
<string name="main_setting_user_logout">注销</string>
<string name="main_setting_logdog">LogDog-罗格狗</string>
<string name="main_device_list_placeholder">点击\"+\"创建新设备</string>
<string name="main_device_this_device">本设备</string>
<string name="global_alert_title_confirm">确认</string>
<string name="alert_device_register_failed_push_sdk">本设备在厂商推送服务注册失败</string>
<string name="main_message_send">发送</string>
<string name="global_alert_title_alert">警告</string>
<string name="main_message_send_alert">发送消息前请创建新的密钥</string>
<string name="global_alert_ok">确认</string>
<string name="global_alert_cancel">取消</string>
<string name="main_key_list_placeholder">点击\"+\"创建新密钥</string>
<string name="main_device_alert_changedevicename">修改设备名称</string>
<string name="main_device_alert_devicename">设备名称</string>
<string name="main_key_alert_changekeyname">修改密钥名称</string>
<string name="main_key_alert_keyname">密钥名称</string>
</resources>

View File

@ -5,4 +5,24 @@
<string name="main_message">Message</string> <string name="main_message">Message</string>
<string name="main_setting">Setting</string> <string name="main_setting">Setting</string>
<string name="global_logdog">LogDog</string> <string name="global_logdog">LogDog</string>
<string name="main_key_reset">Reset</string>
<string name="main_key_copy">Copy</string>
<string name="main_setting_logdog_open">Open</string>
<string name="main_setting_user_hi">Hi</string>
<string name="main_setting_user_logout">Logout</string>
<string name="main_setting_logdog">LogDog</string>
<string name="main_device_list_placeholder">It\'s Empty, Click \'+\' to Add New Device.</string>
<string name="main_device_this_device">this device</string>
<string name="global_alert_title_confirm">Confirm</string>
<string name="alert_device_register_failed_push_sdk">This Device Registered Failed in PushSDK</string>
<string name="main_message_send">Send</string>
<string name="global_alert_title_alert">Alert</string>
<string name="main_message_send_alert">You Should Add One PushKey</string>
<string name="global_alert_ok">OK</string>
<string name="global_alert_cancel">Cancel</string>
<string name="main_key_list_placeholder">It\'s Empty, Click \'+\' to Add New Key.</string>
<string name="main_device_alert_changedevicename">Change Device Name</string>
<string name="main_device_alert_devicename">name</string>
<string name="main_key_alert_changekeyname">Change Key Name</string>
<string name="main_key_alert_keyname">name</string>
</resources> </resources>

View File

@ -6,6 +6,7 @@ buildscript {
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
maven { url 'https://jitpack.io' }
} }
dependencies { dependencies {
classpath "com.android.tools.build:gradle:7.0.4" classpath "com.android.tools.build:gradle:7.0.4"

View File

@ -3,6 +3,7 @@ dependencyResolutionManagement {
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
maven { url 'https://jitpack.io' }
// maven { url 'https://developer.huawei.com/repo/' } // maven { url 'https://developer.huawei.com/repo/' }
} }
} }