diff --git a/android/app/build.gradle b/android/app/build.gradle
index d6c52fc..d6c01db 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -5,14 +5,15 @@ plugins {
}
android {
+
compileSdk 31
defaultConfig {
applicationId "com.pushdeer.os"
minSdk 22
targetSdk 31
- versionCode 5
- versionName "1.0-dev-5"
+ versionCode 8
+ versionName "1.0-dev-8"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
@@ -111,5 +112,7 @@ dependencies {
implementation 'com.github.vishalkumarsinghvi:sign-in-with-apple-button-android:0.6'
- debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.8.1'
+ api 'com.tencent.mm.opensdk:wechat-sdk-android:6.8.0'
+
+// debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.8.1'
}
\ No newline at end of file
diff --git a/android/app/debug/PushDeer-v1.0-dev-8.apk b/android/app/debug/PushDeer-v1.0-dev-8.apk
new file mode 100644
index 0000000..36a7633
Binary files /dev/null and b/android/app/debug/PushDeer-v1.0-dev-8.apk differ
diff --git a/android/app/debug/output-metadata.json b/android/app/debug/output-metadata.json
new file mode 100644
index 0000000..a458e4d
--- /dev/null
+++ b/android/app/debug/output-metadata.json
@@ -0,0 +1,20 @@
+{
+ "version": 3,
+ "artifactType": {
+ "type": "APK",
+ "kind": "Directory"
+ },
+ "applicationId": "com.pushdeer.os",
+ "variantName": "debug",
+ "elements": [
+ {
+ "type": "SINGLE",
+ "filters": [],
+ "attributes": [],
+ "versionCode": 8,
+ "versionName": "1.0-dev-8",
+ "outputFile": "app-debug.apk"
+ }
+ ],
+ "elementType": "File"
+}
\ No newline at end of file
diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro
index a7dd0e8..c37c82e 100644
--- a/android/app/proguard-rules.pro
+++ b/android/app/proguard-rules.pro
@@ -27,4 +27,18 @@
# MiPush
-keep class com.pushdeer.os.receiver.MessageReceiver {*;}
#可以防止一个误报的 warning 导致无法成功编译,如果编译使用的 Android 版本是 23。
--dontwarn com.xiaomi.push.**
\ No newline at end of file
+-dontwarn com.xiaomi.push.**
+
+
+# XiaoErMei
+-keep class com.tencent.mm.opensdk.** {
+ *;
+}
+
+-keep class com.tencent.wxop.** {
+ *;
+}
+
+-keep class com.tencent.mm.sdk.** {
+ *;
+}
\ No newline at end of file
diff --git a/android/app/release/app-release.apk b/android/app/release/app-release.apk
new file mode 100644
index 0000000..c9f9d20
Binary files /dev/null and b/android/app/release/app-release.apk differ
diff --git a/android/app/release/output-metadata.json b/android/app/release/output-metadata.json
new file mode 100644
index 0000000..5432871
--- /dev/null
+++ b/android/app/release/output-metadata.json
@@ -0,0 +1,20 @@
+{
+ "version": 3,
+ "artifactType": {
+ "type": "APK",
+ "kind": "Directory"
+ },
+ "applicationId": "com.pushdeer.os",
+ "variantName": "release",
+ "elements": [
+ {
+ "type": "SINGLE",
+ "filters": [],
+ "attributes": [],
+ "versionCode": 5,
+ "versionName": "1.0-dev-5",
+ "outputFile": "app-release.apk"
+ }
+ ],
+ "elementType": "File"
+}
\ No newline at end of file
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 9bf459d..fa431b3 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -55,6 +55,15 @@
android:theme="@style/Theme.PushDeer.NoActionBar"
/>
+
+
+
override lateinit var requestPermissionOpener: ActivityResultLauncher>
+ val wxRegReceiver: BroadcastReceiver by lazy {
+ object : BroadcastReceiver() {
+ override fun onReceive(context: Context?, intent: Intent?) {
+ intent?.let {
+ when (it.action) {
+ ConstantsAPI.ACTION_REFRESH_WXAPP -> {
+ weChatLogin.iwxapi.registerApp(AppKeys.WX_Id)
+ }
+ WXEntryActivity.ACTION_RETURN_CODE -> {
+ val code = intent.getStringExtra(WXEntryActivity.CODE_KEY)!!
+ lifecycleScope.launch {
+ if (pushDeerViewModel.userInfo.isAppleLogin) {
+ Log.d("WH_", "onReceive: isAppleLogin")
+ // if login, perform merge
+ coroutineScope.launch {
+ pushDeerViewModel.userMerge(
+ "wechat",
+ code
+ ) {
+ coroutineScope.launch {
+ pushDeerViewModel.userInfo()
+ }
+ }
+ }
+ } else {
+ Log.d("WH_", "onReceive: plainLogin")
+ // if not, plain login
+ coroutineScope.launch {
+ pushDeerViewModel.loginWithWeiXin(code) {
+ globalNavController.navigate("main") {
+ globalNavController.popBackStack()
+ }
+ }
+ }
+ }
+ }
+ }
+ else -> {
+ }
+ }
+ }
+
+ }
+ }
+ }
+
@ExperimentalAnimationApi
@ExperimentalMaterialApi
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ registerReceiver(wxRegReceiver,
+ IntentFilter().apply {
+ addAction(ConstantsAPI.ACTION_REFRESH_WXAPP)
+ addAction(WXEntryActivity.ACTION_RETURN_CODE)
+ })
+
+
NotificationUtil.setupChannel(this)
myActivity = this
@@ -124,7 +185,7 @@ class MainActivity : AppCompatActivity(), RequestHolder {
Color.Transparent,
useDarkIcons
)
- else -> systemUiController.setSystemBarsColor(Color.Transparent, useDarkIcons)
+ else -> systemUiController.setSystemBarsColor(Color.Transparent, !useDarkIcons)
}
WindowCompat.setDecorFitsSystemWindows(window, true)
miPushRepository.regId.observe(this) {
@@ -133,7 +194,7 @@ class MainActivity : AppCompatActivity(), RequestHolder {
SideEffect {
coroutineScope.launch {
- pushDeerViewModel.login(onReturn = {
+ pushDeerViewModel.loginWithApple(onReturn = {
globalNavController.navigate("main") {
globalNavController.popBackStack()
}
@@ -165,4 +226,9 @@ class MainActivity : AppCompatActivity(), RequestHolder {
}
}
}
+
+ override fun onDestroy() {
+ super.onDestroy()
+ unregisterReceiver(wxRegReceiver)
+ }
}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/pushdeer/os/data/api/PushDeerApi.kt b/android/app/src/main/java/com/pushdeer/os/data/api/PushDeerApi.kt
index c02b721..60f2097 100644
--- a/android/app/src/main/java/com/pushdeer/os/data/api/PushDeerApi.kt
+++ b/android/app/src/main/java/com/pushdeer/os/data/api/PushDeerApi.kt
@@ -13,7 +13,19 @@ interface PushDeerApi {
@FormUrlEncoded
@POST("/login/idtoken")
- suspend fun loginIdToken(@Field("idToken") idToken: String): ReturnData
+ suspend fun loginWithAppleIdToken(@Field("idToken") idToken: String): ReturnData
+
+ @FormUrlEncoded
+ @POST("/login/wecode")
+ suspend fun loginWithWeXin(@Field("code") code: String): ReturnData
+
+ @FormUrlEncoded
+ @POST("/user/merge")
+ suspend fun userMerge(
+ @Field("token") token: String,
+ @Field("type") type: String, // apple wechat
+ @Field("tokenorcode") tokenorcode: String // input idToken / code
+ ): String
// @GET("/login/fake")
// suspend fun fakeLogin(): ReturnData
diff --git a/android/app/src/main/java/com/pushdeer/os/data/api/data/response/UserInfo.kt b/android/app/src/main/java/com/pushdeer/os/data/api/data/response/UserInfo.kt
index 1358c4e..1fca47b 100644
--- a/android/app/src/main/java/com/pushdeer/os/data/api/data/response/UserInfo.kt
+++ b/android/app/src/main/java/com/pushdeer/os/data/api/data/response/UserInfo.kt
@@ -2,22 +2,44 @@ package com.pushdeer.os.data.api.data.response
class UserInfo {
var id: String = ""
+// var uid: String = ""
var name: String = ""
var email: String = ""
- var app_id: String = ""
- var wechat_id: String = ""
+ var apple_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" +
+// "uid:$uid\n" +
"name:$name\n" +
"email:$email\n" +
- "app_id:$app_id\n" +
+ "apple_id:$apple_id\n" +
"wechat_id:$wechat_id\n" +
"level:$level\n" +
"created:$created_at\n" +
"updated:$updated_at"
}
+
+ val isWeChatLogin: Boolean
+ get() {
+ return if (wechat_id == null) {
+ false
+ } else {
+ wechat_id!!.length > 4
+ }
+ }
+ val isAppleLogin: Boolean
+ get() {
+ return if (apple_id == null) {
+ false
+ } else {
+ apple_id!!.length > 4
+ }
+ }
+
+ val isLogin: Boolean
+ get() = isWeChatLogin or isAppleLogin
}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/pushdeer/os/data/database/dao/LogDogDao.kt b/android/app/src/main/java/com/pushdeer/os/data/database/dao/LogDogDao.kt
index da0ae3a..f2ac3de 100644
--- a/android/app/src/main/java/com/pushdeer/os/data/database/dao/LogDogDao.kt
+++ b/android/app/src/main/java/com/pushdeer/os/data/database/dao/LogDogDao.kt
@@ -15,6 +15,9 @@ interface LogDogDao {
@Insert
suspend fun insert(vararg logDog: LogDog)
+ @Insert
+ fun insert1(vararg logDog: LogDog)
+
@Query("delete from LogDog")
suspend fun clear()
}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/pushdeer/os/data/database/entity/LogDog.kt b/android/app/src/main/java/com/pushdeer/os/data/database/entity/LogDog.kt
index 960c90a..b7bbc5c 100644
--- a/android/app/src/main/java/com/pushdeer/os/data/database/entity/LogDog.kt
+++ b/android/app/src/main/java/com/pushdeer/os/data/database/entity/LogDog.kt
@@ -18,6 +18,7 @@ class LogDog {
return "id:$id\n" +
"level:$level\n" +
"entity:$entity\n" +
+ "event:$event\n" +
"log:$log\n" +
"time:${timestamp.toTimestamp()}"
}
diff --git a/android/app/src/main/java/com/pushdeer/os/data/repository/LogDogRepository.kt b/android/app/src/main/java/com/pushdeer/os/data/repository/LogDogRepository.kt
index c3492aa..799f455 100644
--- a/android/app/src/main/java/com/pushdeer/os/data/repository/LogDogRepository.kt
+++ b/android/app/src/main/java/com/pushdeer/os/data/repository/LogDogRepository.kt
@@ -2,13 +2,14 @@ package com.pushdeer.os.data.repository
import com.pushdeer.os.data.database.dao.LogDogDao
import com.pushdeer.os.data.database.entity.LogDog
+import com.pushdeer.os.store.SettingStore
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
-class LogDogRepository(private val logDogDao: LogDogDao) {
+class LogDogRepository(private val logDogDao: LogDogDao,private val settingStore: SettingStore) {
val all = logDogDao.all
- suspend fun clear(){
+ suspend fun clear() {
logDogDao.clear()
}
@@ -28,6 +29,20 @@ class LogDogRepository(private val logDogDao: LogDogDao) {
}
}
+ fun log(
+ entity: String,
+ level: String,
+ event: String,
+ log: String
+ ) {
+ logDogDao.insert1(LogDog().apply {
+ this.entity = entity
+ this.level = level
+ this.event = event
+ this.log = log
+ })
+ }
+
suspend fun logi(entity: String, event: String, log: String) {
withContext(Dispatchers.IO) {
insert(LogDog.logi(entity, event, log))
diff --git a/android/app/src/main/java/com/pushdeer/os/holder/RequestHolder.kt b/android/app/src/main/java/com/pushdeer/os/holder/RequestHolder.kt
index 6f53489..1386e27 100644
--- a/android/app/src/main/java/com/pushdeer/os/holder/RequestHolder.kt
+++ b/android/app/src/main/java/com/pushdeer/os/holder/RequestHolder.kt
@@ -4,6 +4,7 @@ import android.content.ClipData
import android.content.ClipboardManager
import android.content.Intent
import android.content.res.Resources
+import android.util.Log
import androidx.activity.result.ActivityResultLauncher
import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity
@@ -23,7 +24,12 @@ import com.pushdeer.os.viewmodel.LogDogViewModel
import com.pushdeer.os.viewmodel.MessageViewModel
import com.pushdeer.os.viewmodel.PushDeerViewModel
import com.pushdeer.os.viewmodel.UiViewModel
+import com.tencent.mm.opensdk.modelmsg.SendAuth
+import com.tencent.mm.opensdk.openapi.IWXAPI
import com.wh.common.activity.QrScanActivity
+import com.willowtreeapps.signinwithapplebutton.SignInWithAppleConfiguration
+import com.willowtreeapps.signinwithapplebutton.SignInWithAppleResult
+import com.willowtreeapps.signinwithapplebutton.SignInWithAppleService
import io.noties.markwon.Markwon
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
@@ -40,16 +46,20 @@ interface RequestHolder {
val myActivity: AppCompatActivity
val markdown: Markwon
val qrScanActivityOpener: ActivityResultLauncher
- val requestPermissionOpener:ActivityResultLauncher>
+ val requestPermissionOpener: ActivityResultLauncher>
val coilImageLoader: ImageLoader
- val fragmentManager: FragmentManager
+ // requests
val alert: AlertRequest
- val key:KeyRequest
- val device:DeviceRequest
- val message:MessageRequest
- val clip:ClipRequest
+ val key: KeyRequest
+ val device: DeviceRequest
+ val message: MessageRequest
+ val clip: ClipRequest
+ val weChatLogin: WeChatLoginRequest
+ val appleLogin: AppleLoginRequest
+
+// val iwxapi: IWXAPI
fun startQrScanActivity() {
qrScanActivityOpener.launch(QrScanActivity.forScanResultIntent(myActivity))
@@ -61,29 +71,98 @@ interface RequestHolder {
}
fun clearLogDog() {
- alert.alert(R.string.global_alert_title_confirm,"Clear?",onOk = {
- logDogViewModel.clear()
+ alert.alert(R.string.global_alert_title_confirm, "Clear?", onOk = {
+ logDogViewModel.clear()
})
}
- fun userRename(newName:String){
+ abstract class AppleLoginRequest(
+ private val fragmentManager: FragmentManager,
+ private val requestHolder: RequestHolder
+ ) {
+ private val appleLoginCallBack: (SignInWithAppleResult) -> Unit =
+ { result: SignInWithAppleResult ->
+ when (result) {
+ is SignInWithAppleResult.Success -> {
+ if (requestHolder.pushDeerViewModel.userInfo.isWeChatLogin) {
+ // if login with wechat, perform merge
+ requestHolder.coroutineScope.launch {
+ requestHolder.pushDeerViewModel.userMerge(
+ type = "apple",
+ tokenorcode = result.idToken,
+ onReturn = {
+ requestHolder.coroutineScope.launch {
+ requestHolder.pushDeerViewModel.userInfo()
+ }
+ }
+ )
+ }
+ } else {
+ // else ( is not login ), plain login with apple
+ requestHolder.coroutineScope.launch {
+ requestHolder.pushDeerViewModel.loginWithApple(result.idToken) {
+ requestHolder.globalNavController.navigate("main") {
+ requestHolder.globalNavController.popBackStack()
+ }
+ }
+ }
+ }
+ }
+ is SignInWithAppleResult.Failure -> {
+ requestHolder.alert.alert("Warning Apple Id Login Failed", {
+ result.error.message
+ }, onOk = {})
+ Log.d(
+ "WH_",
+ "Received error from Apple Sign In ${result.error.message}"
+ )
+ }
+ is SignInWithAppleResult.Cancel -> {
+ Log.d("WH_", "User canceled Apple Sign In")
+ }
+ }
+ }
+ private val appleLoginConfiguration = SignInWithAppleConfiguration.Builder()
+ .clientId("com.pushdeer.site")
+ .redirectUri("https://api2.pushdeer.com/callback/apple")
+ .responseType(SignInWithAppleConfiguration.ResponseType.ALL)
+ .scope(SignInWithAppleConfiguration.Scope.EMAIL)
+ .build()
+
+ val login = {
+ val service = SignInWithAppleService(
+ fragmentManager = fragmentManager,
+ fragmentTag = "SignInWithAppleButton-1-SignInWebViewDialogFragment",
+ configuration = appleLoginConfiguration,
+ callback = appleLoginCallBack
+ )
+ service.show()
+ }
}
-// abstract class LogDogRequest(private val )
+ abstract class WeChatLoginRequest(val iwxapi: IWXAPI) {
+ val login: () -> Unit = {
+ val req = SendAuth.Req()
+ req.scope = "snsapi_userinfo"
+ req.state = System.currentTimeMillis().toString()
+ iwxapi.sendReq(req)
+ }
+ }
abstract class ClipRequest(private val clipboardManager: ClipboardManager) {
fun copyMessagePlainText(str: String) {
clipboardManager.setPrimaryClip(ClipData.newPlainText("pushdeer-copy-plain-text", str))
}
- fun copyPushKey(str: String){
+ fun copyPushKey(str: String) {
clipboardManager.setPrimaryClip(ClipData.newPlainText("pushdeer-copy-pushkey", str))
}
}
abstract class AlertRequest(private val resources: Resources) {
- val show: MutableState = mutableStateOf(false)
+ val show2BtnDialog: MutableState = mutableStateOf(false)
+ val show1BtnDialog: MutableState = mutableStateOf(false)
var title: String = ""
var content: @Composable () -> Unit = {}
var onOKAction: () -> Unit = {}
@@ -94,19 +173,34 @@ interface RequestHolder {
title: String,
content: @Composable () -> Unit,
onOk: () -> Unit,
- onCancel: () -> Unit = {}
+ ) {
+ this.title = title
+ this.content = content
+ this.onOKAction = onOk
+ this.show1BtnDialog.value = true
+ }
+
+ 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
+ this.show2BtnDialog.value = true
}
fun alert(title: String, content: String, onOk: () -> Unit, onCancel: () -> Unit = {}) {
alert(title, { Text(text = content) }, onOk, onCancel)
}
+ fun alert(title: String, content: String, onOk: () -> Unit) {
+ alert(title, { Text(text = content) }, onOk)
+ }
+
fun alert(
@StringRes title: Int,
@StringRes content: Int,
@@ -116,6 +210,14 @@ interface RequestHolder {
alert(resources.getString(title), resources.getString(content), onOk, onCancel)
}
+ fun alert(
+ @StringRes title: Int,
+ @StringRes content: Int,
+ onOk: () -> Unit = {},
+ ) {
+ alert(resources.getString(title), resources.getString(content), onOk)
+ }
+
fun alert(
@StringRes title: Int,
content: @Composable () -> Unit,
@@ -125,6 +227,14 @@ interface RequestHolder {
alert(resources.getString(title), content, onOk, onCancel)
}
+ fun alert(
+ @StringRes title: Int,
+ content: @Composable () -> Unit,
+ onOk: () -> Unit,
+ ) {
+ alert(resources.getString(title), content, onOk)
+ }
+
fun alert(
@StringRes title: Int,
content: String,
@@ -133,9 +243,17 @@ interface RequestHolder {
) {
alert(resources.getString(title), content, onOk, onCancel)
}
+
+ fun alert(
+ @StringRes title: Int,
+ content: String,
+ onOk: () -> Unit,
+ ) {
+ alert(resources.getString(title), content, onOk)
+ }
}
- abstract class KeyRequest(private val requestHolder: RequestHolder){
+ abstract class KeyRequest(private val requestHolder: RequestHolder) {
fun gen() {
requestHolder.coroutineScope.launch {
requestHolder.pushDeerViewModel.keyGen()
@@ -166,7 +284,7 @@ interface RequestHolder {
}
}
- abstract class DeviceRequest(private val requestHolder: RequestHolder){
+ abstract class DeviceRequest(private val requestHolder: RequestHolder) {
fun deviceReg(deviceInfo: DeviceInfo) {
requestHolder.coroutineScope.launch {
requestHolder.pushDeerViewModel.deviceReg(deviceInfo)
@@ -191,7 +309,7 @@ interface RequestHolder {
}
}
- abstract class MessageRequest(private val requestHolder: RequestHolder){
+ 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)
@@ -200,16 +318,21 @@ interface RequestHolder {
fun messagePushTest(text: String) {
if (requestHolder.pushDeerViewModel.keyList.isNotEmpty()) {
- messagePush(text, "pushtest", "markdown", requestHolder.pushDeerViewModel.keyList[0].key)
+ messagePush(
+ text,
+ "pushtest",
+ "markdown",
+ requestHolder.pushDeerViewModel.keyList[0].key
+ )
requestHolder.coroutineScope.launch {
- delay(1000)
+ delay(900)
requestHolder.pushDeerViewModel.messageList()
}
} else {
requestHolder.alert.alert(
R.string.global_alert_title_alert,
- R.string.main_message_send_alert,
- onOk = {})
+ R.string.main_message_send_alert
+ )
}
}
diff --git a/android/app/src/main/java/com/pushdeer/os/keeper/RepositoryKeeper.kt b/android/app/src/main/java/com/pushdeer/os/keeper/RepositoryKeeper.kt
index cd01fd2..77cc712 100644
--- a/android/app/src/main/java/com/pushdeer/os/keeper/RepositoryKeeper.kt
+++ b/android/app/src/main/java/com/pushdeer/os/keeper/RepositoryKeeper.kt
@@ -4,9 +4,10 @@ import com.pushdeer.os.data.database.AppDatabase
import com.pushdeer.os.data.repository.LogDogRepository
import com.pushdeer.os.data.repository.MessageRepository
import com.pushdeer.os.data.repository.MiPushRepository
+import com.pushdeer.os.store.SettingStore
-class RepositoryKeeper(database: AppDatabase) {
+class RepositoryKeeper(database: AppDatabase,settingStore: SettingStore) {
val miPushRepository = MiPushRepository()
- val logDogRepository = LogDogRepository(database.logDogDao())
+ val logDogRepository = LogDogRepository(database.logDogDao(),settingStore)
val messageRepository = MessageRepository(database.messageDao())
}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/pushdeer/os/okhttp/LogInterceptor.kt b/android/app/src/main/java/com/pushdeer/os/okhttp/LogInterceptor.kt
new file mode 100644
index 0000000..472b230
--- /dev/null
+++ b/android/app/src/main/java/com/pushdeer/os/okhttp/LogInterceptor.kt
@@ -0,0 +1,23 @@
+package com.pushdeer.os.okhttp
+
+import android.util.Log
+import com.pushdeer.os.data.repository.LogDogRepository
+import okhttp3.Interceptor
+import okhttp3.Response
+
+class LogInterceptor(private val logDogRepository: LogDogRepository): Interceptor{
+ override fun intercept(chain: Interceptor.Chain): Response {
+ val request = chain.request()
+
+ val url = request.url
+ val methods = request.method
+ val isHttps = request.isHttps
+ val contentType = request.body?.contentType()
+
+ val response = chain.proceed(request)
+
+ Log.d("WH_", "intercept: $response.")
+
+ return response
+ }
+}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/pushdeer/os/store/SettingStore.kt b/android/app/src/main/java/com/pushdeer/os/store/SettingStore.kt
index 3bdc95d..387c474 100644
--- a/android/app/src/main/java/com/pushdeer/os/store/SettingStore.kt
+++ b/android/app/src/main/java/com/pushdeer/os/store/SettingStore.kt
@@ -18,4 +18,6 @@ class SettingStore(context:Context) {
var showMessageSender by store.boolean("show-message-sender",true)
var thisPushSdk by store.string("this-push-sdk","mi-push")
var thisDeviceId by store.string("this-device-id","")
+
+ var logLevel by store.string("log-level","i") // i w e - d
}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/pushdeer/os/ui/compose/componment/Item.kt b/android/app/src/main/java/com/pushdeer/os/ui/compose/componment/Item.kt
index 418ecf6..579d6e5 100644
--- a/android/app/src/main/java/com/pushdeer/os/ui/compose/componment/Item.kt
+++ b/android/app/src/main/java/com/pushdeer/os/ui/compose/componment/Item.kt
@@ -30,12 +30,12 @@ fun CardItemSingleLineWithIcon(
) {
Card(
onClick = onClick,
- shape = RoundedCornerShape(4.dp),
+ shape = RoundedCornerShape(8.dp),
modifier = Modifier
.border(
width = 1.dp,
color = MainBlue,
- shape = RoundedCornerShape(4.dp)
+ shape = RoundedCornerShape(8.dp)
),
elevation = 5.dp
@@ -72,13 +72,13 @@ fun CardItemMultiLine(
) {
Card(
onClick = onClick,
- shape = RoundedCornerShape(4.dp),
+ shape = RoundedCornerShape(8.dp),
modifier = Modifier
// .padding(bottom = 16.dp)
.border(
width = 1.dp,
color = MainBlue,
- shape = RoundedCornerShape(4.dp)
+ shape = RoundedCornerShape(8.dp)
),
elevation = 5.dp
@@ -111,12 +111,12 @@ fun CardItemMultiLine(
fun CardItemWithContent(onClick: () -> Unit, content: @Composable () -> Unit = {}) {
Card(
onClick = onClick,
- shape = RoundedCornerShape(4.dp),
+ shape = RoundedCornerShape(8.dp),
modifier = Modifier
.border(
width = 1.dp,
color = MainBlue,
- shape = RoundedCornerShape(4.dp)
+ shape = RoundedCornerShape(8.dp)
),
content = content,
elevation = 5.dp
@@ -127,12 +127,12 @@ fun CardItemWithContent(onClick: () -> Unit, content: @Composable () -> Unit = {
@Composable
fun CardItemWithContent(content: @Composable () -> Unit = {}) {
Card(
- shape = RoundedCornerShape(4.dp),
+ shape = RoundedCornerShape(8.dp),
modifier = Modifier
.border(
width = 1.dp,
color = MainBlue,
- shape = RoundedCornerShape(4.dp)
+ shape = RoundedCornerShape(8.dp)
),
content = content,
elevation = 5.dp
diff --git a/android/app/src/main/java/com/pushdeer/os/ui/compose/componment/KeyItem.kt b/android/app/src/main/java/com/pushdeer/os/ui/compose/componment/KeyItem.kt
index d40b555..b3780b6 100644
--- a/android/app/src/main/java/com/pushdeer/os/ui/compose/componment/KeyItem.kt
+++ b/android/app/src/main/java/com/pushdeer/os/ui/compose/componment/KeyItem.kt
@@ -176,7 +176,7 @@ fun KeyItem(key: PushKey, requestHolder: RequestHolder) {
backgroundColor = MaterialTheme.colors.MBlue,
contentColor = Color.White
),
- shape = RoundedCornerShape(6.dp)
+ shape = RoundedCornerShape(8.dp)
) {
Text(text = stringResource(id = R.string.main_key_copy))
}
diff --git a/android/app/src/main/java/com/pushdeer/os/ui/compose/componment/MessageItem.kt b/android/app/src/main/java/com/pushdeer/os/ui/compose/componment/MessageItem.kt
index c8ca6a2..1a0407b 100644
--- a/android/app/src/main/java/com/pushdeer/os/ui/compose/componment/MessageItem.kt
+++ b/android/app/src/main/java/com/pushdeer/os/ui/compose/componment/MessageItem.kt
@@ -33,7 +33,7 @@ fun PlainTextMessageItem(message: MessageEntity,requestHolder: RequestHolder) {
Column(
modifier = Modifier
.fillMaxWidth()
- .clip(RoundedCornerShape(4.dp))
+ .clip(RoundedCornerShape(8.dp))
.clickable {
requestHolder.clip.copyMessagePlainText(message.text)
}
@@ -80,7 +80,7 @@ fun ImageMessageItem(message: MessageEntity, requestHolder: RequestHolder) {
Column(
modifier = Modifier
.fillMaxWidth()
- .clip(RoundedCornerShape(4.dp))
+ .clip(RoundedCornerShape(8.dp))
.clickable {
requestHolder.clip.copyMessagePlainText(message.text)
}
@@ -125,7 +125,7 @@ fun MarkdownMessageItem(message: MessageEntity, requestHolder: RequestHolder) {
Column(
modifier = Modifier
.fillMaxWidth()
- .clip(RoundedCornerShape(4.dp))
+ .clip(RoundedCornerShape(8.dp))
.clickable {
requestHolder.clip.copyMessagePlainText(message.text)
}
diff --git a/android/app/src/main/java/com/pushdeer/os/ui/compose/componment/MyAlertDialog.kt b/android/app/src/main/java/com/pushdeer/os/ui/compose/componment/MyAlertDialog.kt
index 8a428d4..79865c8 100644
--- a/android/app/src/main/java/com/pushdeer/os/ui/compose/componment/MyAlertDialog.kt
+++ b/android/app/src/main/java/com/pushdeer/os/ui/compose/componment/MyAlertDialog.kt
@@ -10,13 +10,13 @@ import com.pushdeer.os.holder.RequestHolder
@Composable
fun MyAlertDialog(alertRequest: RequestHolder.AlertRequest) {
- if (alertRequest.show.value) {
+ if (alertRequest.show2BtnDialog.value) {
AlertDialog(
- onDismissRequest = { alertRequest.show.value = false },
+ onDismissRequest = { alertRequest.show2BtnDialog.value = false },
confirmButton = {
TextButton(onClick = {
alertRequest.onOKAction.invoke()
- alertRequest.show.value = false
+ alertRequest.show2BtnDialog.value = false
}) {
Text(text = stringResource(id = R.string.global_alert_ok))
}
@@ -25,7 +25,7 @@ fun MyAlertDialog(alertRequest: RequestHolder.AlertRequest) {
dismissButton = {
TextButton(onClick = {
alertRequest.onCancelAction.invoke()
- alertRequest.show.value = false
+ alertRequest.show2BtnDialog.value = false
}) {
Text(text = stringResource(id = R.string.global_alert_cancel))
}
@@ -35,4 +35,20 @@ fun MyAlertDialog(alertRequest: RequestHolder.AlertRequest) {
text = alertRequest.content
)
}
+ if (alertRequest.show1BtnDialog.value){
+ AlertDialog(
+ onDismissRequest = { alertRequest.show1BtnDialog.value = false },
+ confirmButton = {
+ TextButton(onClick = {
+ alertRequest.onOKAction.invoke()
+ alertRequest.show1BtnDialog.value = false
+ }) {
+ Text(text = stringResource(id = R.string.global_alert_ok))
+ }
+
+ },
+ title = { Text(text = alertRequest.title) },
+ text = alertRequest.content
+ )
+ }
}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/pushdeer/os/ui/compose/componment/SettingItem.kt b/android/app/src/main/java/com/pushdeer/os/ui/compose/componment/SettingItem.kt
index 3535f9f..bfde477 100644
--- a/android/app/src/main/java/com/pushdeer/os/ui/compose/componment/SettingItem.kt
+++ b/android/app/src/main/java/com/pushdeer/os/ui/compose/componment/SettingItem.kt
@@ -14,11 +14,17 @@ import com.pushdeer.os.ui.theme.MBlue
@ExperimentalMaterialApi
@Composable
-fun SettingItem(text: String, buttonString: String, onItemClick:()->Unit={},onButtonClick: () -> Unit) {
+fun SettingItem(
+ text: String,
+ buttonString: String,
+ onItemClick: () -> Unit = {},
+ paddingValues: PaddingValues = PaddingValues(bottom = 16.dp),
+ onButtonClick: () -> Unit
+) {
Column(
modifier = Modifier
.fillMaxWidth()
- .padding(bottom = 16.dp)
+ .padding(paddingValues)
) {
CardItemWithContent(onClick = onItemClick) {
Row(
@@ -51,4 +57,21 @@ fun SettingItem(text: String, buttonString: String, onItemClick:()->Unit={},onBu
}
}
}
-}
\ No newline at end of file
+}
+
+//@ExperimentalMaterialApi
+//@Composable
+//fun SettingItem(content: @Composable () -> Unit) {
+// Card(
+// onClick = onClick,
+// shape = RoundedCornerShape(4.dp),
+// modifier = Modifier
+// .border(
+// width = 1.dp,
+// color = MainBlue,
+// shape = RoundedCornerShape(4.dp)
+// ),
+// content = content,
+// elevation = 5.dp
+// )
+//}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/pushdeer/os/ui/compose/componment/SwipeToDismissItem.kt b/android/app/src/main/java/com/pushdeer/os/ui/compose/componment/SwipeToDismissItem.kt
index 7145826..4f23325 100644
--- a/android/app/src/main/java/com/pushdeer/os/ui/compose/componment/SwipeToDismissItem.kt
+++ b/android/app/src/main/java/com/pushdeer/os/ui/compose/componment/SwipeToDismissItem.kt
@@ -1,82 +1,110 @@
package com.pushdeer.os.ui.compose.componment
-import androidx.compose.animation.animateColorAsState
+import androidx.compose.animation.*
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.Delete
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
+import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
-import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
+import com.pushdeer.os.holder.RequestHolder
+import com.pushdeer.os.ui.theme.SwipeToDismissGray
+import com.pushdeer.os.ui.theme.SwipeToDismissRed
import com.pushdeer.os.values.ConstValues
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
@ExperimentalMaterialApi
@Composable
fun SwipeToDismissItem(
onAction: () -> Unit,
sidePadding: Boolean = false,
+ requestHolder: RequestHolder,
content: @Composable RowScope.() -> Unit
) {
- val dismissState = rememberDismissState()
- if (dismissState.isDismissed(DismissDirection.EndToStart)) {
- onAction()
+ var visible by remember {
+ mutableStateOf(true)
}
- Column(modifier = Modifier
- .fillMaxWidth()
- .padding(bottom = 16.dp)) {
- SwipeToDismiss(
- state = dismissState,
- background = {
-// val direction = dismissState.dismissDirection ?: return@SwipeToDismiss
+ val dismissv = DismissValue.Default
+ val dismissState = rememberDismissState(initialValue = dismissv)
+ LaunchedEffect(Unit){
+ if (dismissState.isDismissed(DismissDirection.EndToStart)){
+ requestHolder.coroutineScope.launch {
+ dismissState.reset()
+ }
+ }
+ }
+ AnimatedVisibility(
+ visible = visible,
+ enter = fadeIn() + expandVertically(),
+ exit = fadeOut() + shrinkVertically()
+ ) {
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(bottom = 16.dp)
+ ) {
- val color by animateColorAsState(
- when (dismissState.targetValue) {
- DismissValue.DismissedToEnd -> Color.Green
- DismissValue.DismissedToStart -> Color.Red
- else -> Color.Gray
- }
- )
+ SwipeToDismiss(
+ state = dismissState,
+ background = {
-// val alignment = when (direction) {
-// DismissDirection.StartToEnd -> Alignment.CenterStart
-// DismissDirection.EndToStart -> Alignment.CenterEnd
-// }
-//
-// val icon = when (direction) {
-// DismissDirection.StartToEnd -> Icons.Default.Done
-// DismissDirection.EndToStart -> Icons.Default.Delete
-// }
-
- val alignment = Alignment.CenterEnd
- val icon = Icons.Default.Delete
-
- Box(
- contentAlignment = alignment,
- modifier = Modifier
- .fillMaxSize()
- .clip(RoundedCornerShape(4.dp))
- .background(color)
- .padding(end = 32.dp)
- ) {
- Icon(
- imageVector = icon,
- contentDescription = "",
-// tint = Color.Red
+ val color by animateColorAsState(
+ when (dismissState.targetValue) {
+ DismissValue.DismissedToEnd -> SwipeToDismissGray
+ DismissValue.DismissedToStart -> SwipeToDismissRed
+ else -> SwipeToDismissGray
+ }
)
- }
- },
- directions = setOf(DismissDirection.EndToStart),
- dismissThresholds = { direction ->
- FractionalThreshold(if (direction == DismissDirection.EndToStart) 0.45f else 0.57f)
- },
- dismissContent = content,
- modifier = Modifier.padding(horizontal = if (sidePadding) ConstValues.MainPageSidePadding else 0.dp)
- )
+
+ Row(
+ modifier = Modifier
+ .fillMaxSize()
+ .clip(RoundedCornerShape(8.dp))
+ .background(color)
+ .padding(end = 32.dp),
+ horizontalArrangement = Arrangement.End,
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ IconButton(onClick = {
+ requestHolder.coroutineScope.launch {
+ dismissState.reset()
+ }
+ }) {
+ Icon(
+ imageVector = Icons.Default.ArrowBack,
+ contentDescription = "",
+ )
+ }
+ IconButton(onClick = {
+ visible = false
+
+ requestHolder.coroutineScope.launch {
+ delay(300)
+ onAction()
+ }
+ }) {
+ Icon(
+ imageVector = Icons.Default.Delete,
+ contentDescription = "",
+ )
+ }
+ }
+ },
+ directions = setOf(DismissDirection.EndToStart),
+ dismissThresholds = {
+ FractionalThreshold(0.45f)
+ },
+ dismissContent = content,
+ modifier = Modifier.padding(horizontal = if (sidePadding) ConstValues.MainPageSidePadding else 0.dp)
+ )
+ }
+
}
}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/pushdeer/os/ui/compose/componment/WeChatLoginButtom.kt b/android/app/src/main/java/com/pushdeer/os/ui/compose/componment/WeChatLoginButtom.kt
new file mode 100644
index 0000000..9928648
--- /dev/null
+++ b/android/app/src/main/java/com/pushdeer/os/ui/compose/componment/WeChatLoginButtom.kt
@@ -0,0 +1,43 @@
+package com.pushdeer.os.ui.compose.componment
+
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.viewinterop.AndroidView
+import com.willowtreeapps.signinwithapplebutton.view.SignInWithAppleButton
+
+@Composable
+fun WeChatLoginButton() {
+ Row(
+ modifier = Modifier
+ .clip(RoundedCornerShape(4.dp))
+ .border(BorderStroke(1.dp, color = Color.Green), shape = RoundedCornerShape(4.dp))
+ .background(color = Color.Green)
+ .width((150).dp)
+ .height(38.dp)
+ ) {
+ Text(text = "aaa")
+ }
+}
+
+@Preview(showBackground = true)
+@Composable
+fun W() {
+ Row {
+ WeChatLoginButton()
+ AndroidView(factory = {
+ SignInWithAppleButton(it)
+ }, modifier = Modifier.border(1.dp, color = Color.Black, shape = RoundedCornerShape(4.dp)))
+ }
+}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/pushdeer/os/ui/compose/page/LoginPage.kt b/android/app/src/main/java/com/pushdeer/os/ui/compose/page/LoginPage.kt
index cfb79d6..c08ef80 100644
--- a/android/app/src/main/java/com/pushdeer/os/ui/compose/page/LoginPage.kt
+++ b/android/app/src/main/java/com/pushdeer/os/ui/compose/page/LoginPage.kt
@@ -1,37 +1,31 @@
package com.pushdeer.os.ui.compose.page
-import android.util.Log
import androidx.compose.foundation.Image
+import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
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.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
-import androidx.compose.ui.viewinterop.AndroidView
import com.pushdeer.os.R
import com.pushdeer.os.holder.RequestHolder
-import com.willowtreeapps.signinwithapplebutton.SignInWithAppleConfiguration
-import com.willowtreeapps.signinwithapplebutton.SignInWithAppleResult
-import com.willowtreeapps.signinwithapplebutton.view.SignInWithAppleButton
-import kotlinx.coroutines.launch
+import com.pushdeer.os.ui.theme.MainGreen
@ExperimentalMaterialApi
@Composable
fun LoginPage(requestHolder: RequestHolder) {
Box(modifier = Modifier.fillMaxSize()) {
-
- 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(
painter = painterResource(R.drawable.logo_com_x2),
contentDescription = "big push deer logo",
@@ -40,43 +34,50 @@ fun LoginPage(requestHolder: RequestHolder) {
.align(Alignment.TopCenter)
.padding(top = 50.dp)
)
- AndroidView(
- factory = {
- SignInWithAppleButton(it).apply {
- setUpSignInWithAppleOnClick(
- requestHolder.fragmentManager,
- configuration
- ) { result ->
- when (result) {
- is SignInWithAppleResult.Success -> {
- Log.d("WH_", "apple-id_token:${result.idToken}")
- requestHolder.coroutineScope.launch {
- requestHolder.pushDeerViewModel.login(result.idToken) {
- requestHolder.globalNavController.navigate("main") {
- requestHolder.globalNavController.popBackStack()
- }
- }
- }
- }
- is SignInWithAppleResult.Failure -> {
- requestHolder.alert.alert("Warning Apple Id Login Failed", {
- result.error.message
- }, onOk = {})
- Log.d(
- "WH_",
- "Received error from Apple Sign In ${result.error.message}"
- )
- }
- is SignInWithAppleResult.Cancel -> {
- Log.d("WH_", "User canceled Apple Sign In")
- }
- }
- }
- }
- },
+ Card(
+ onClick = requestHolder.weChatLogin.login,
+ shape = RoundedCornerShape(4.dp),
modifier = Modifier
+ .padding(bottom = 220.dp)
+ .border(
+ width = 1.dp,
+ color = MainGreen,
+ shape = RoundedCornerShape(4.dp)
+ )
.align(alignment = Alignment.BottomCenter)
- .padding(bottom = 100.dp)
- )
+
+ ) {
+ Text(
+ text = "Sign in with WeChat",
+ color = MainGreen,
+ textAlign = TextAlign.Center,
+ modifier = Modifier
+ .padding(vertical = 16.dp)
+ .fillMaxWidth(0.6F)
+ )
+ }
+
+ Card(
+ onClick = requestHolder.appleLogin.login,
+ shape = RoundedCornerShape(4.dp),
+ modifier = Modifier
+ .padding(bottom = 140.dp)
+ .border(
+ width = 1.dp,
+ color = Color.Black,
+ shape = RoundedCornerShape(4.dp)
+ )
+ .align(alignment = Alignment.BottomCenter)
+
+ ) {
+ Text(
+ text = "Sign in with Apple",
+ color = Color.Black,
+ textAlign = TextAlign.Center,
+ modifier = Modifier
+ .padding(vertical = 16.dp)
+ .fillMaxWidth(0.6F)
+ )
+ }
}
}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/pushdeer/os/ui/compose/page/main/DeviceListPage.kt b/android/app/src/main/java/com/pushdeer/os/ui/compose/page/main/DeviceListPage.kt
index 66ed18f..dbca9ac 100644
--- a/android/app/src/main/java/com/pushdeer/os/ui/compose/page/main/DeviceListPage.kt
+++ b/android/app/src/main/java/com/pushdeer/os/ui/compose/page/main/DeviceListPage.kt
@@ -72,12 +72,13 @@ fun DeviceListPage(requestHolder: RequestHolder) {
val state = rememberLazyListState()
LazyColumn(state = state) {
items(
- items = requestHolder.pushDeerViewModel.deviceList,
+ items = requestHolder.pushDeerViewModel.deviceList.sortedByDescending { it.id },
key = { item: DeviceInfo -> item.id }) { deviceInfo: DeviceInfo ->
var name by remember {
mutableStateOf(deviceInfo.name)
}
SwipeToDismissItem(
+ requestHolder = requestHolder,
onAction = { requestHolder.device.deviceRemove(deviceInfo) }
) {
CardItemSingleLineWithIcon(
diff --git a/android/app/src/main/java/com/pushdeer/os/ui/compose/page/main/KeyListPage.kt b/android/app/src/main/java/com/pushdeer/os/ui/compose/page/main/KeyListPage.kt
index 3a04287..d346db7 100644
--- a/android/app/src/main/java/com/pushdeer/os/ui/compose/page/main/KeyListPage.kt
+++ b/android/app/src/main/java/com/pushdeer/os/ui/compose/page/main/KeyListPage.kt
@@ -49,9 +49,11 @@ fun KeyListPage(requestHolder: RequestHolder) {
}else{
LazyColumn(modifier = Modifier.fillMaxWidth()) {
items(
- requestHolder.pushDeerViewModel.keyList,
+ requestHolder.pushDeerViewModel.keyList.sortedBy { it.id },
key = { item: PushKey -> item.id }) { pushKey: PushKey ->
- SwipeToDismissItem(onAction = { requestHolder.key.remove(pushKey) }
+ SwipeToDismissItem(
+ requestHolder = requestHolder,
+ onAction = { requestHolder.key.remove(pushKey) }
) {
KeyItem(key = pushKey, requestHolder = requestHolder)
}
diff --git a/android/app/src/main/java/com/pushdeer/os/ui/compose/page/main/MainPageFrame.kt b/android/app/src/main/java/com/pushdeer/os/ui/compose/page/main/MainPageFrame.kt
index 40af90b..ac73188 100644
--- a/android/app/src/main/java/com/pushdeer/os/ui/compose/page/main/MainPageFrame.kt
+++ b/android/app/src/main/java/com/pushdeer/os/ui/compose/page/main/MainPageFrame.kt
@@ -24,6 +24,7 @@ fun MainPageFrame(
titleStringId: Int,
showSideIcon: Boolean = true,
sideIcon: ImageVector = Icons.Default.Add,
+ iconModifier: Modifier = Modifier,
onSideIconClick: () -> Unit = {},
sidePadding: Boolean = true,
content: @Composable BoxScope.() -> Unit
@@ -53,7 +54,8 @@ fun MainPageFrame(
Icon(
imageVector = sideIcon,
contentDescription = "",
- tint = Color.LightGray
+ tint = Color.LightGray,
+ modifier = iconModifier
)
}
// }
diff --git a/android/app/src/main/java/com/pushdeer/os/ui/compose/page/main/MessageListPage.kt b/android/app/src/main/java/com/pushdeer/os/ui/compose/page/main/MessageListPage.kt
index 9aa9e15..64b3e98 100644
--- a/android/app/src/main/java/com/pushdeer/os/ui/compose/page/main/MessageListPage.kt
+++ b/android/app/src/main/java/com/pushdeer/os/ui/compose/page/main/MessageListPage.kt
@@ -1,6 +1,7 @@
package com.pushdeer.os.ui.compose.page.main
import androidx.compose.animation.*
+import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
@@ -10,9 +11,9 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.KeyboardArrowDown
-import androidx.compose.material.icons.filled.KeyboardArrowUp
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.rotate
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
@@ -37,9 +38,14 @@ fun MessageListPage(requestHolder: RequestHolder) {
}
}
+// val a = rotat
+
+ val a by animateFloatAsState(targetValue = if (requestHolder.uiViewModel.showMessageSender) 0F else 180F)
+
MainPageFrame(
titleStringId = Page.Messages.labelStringId,
- sideIcon = if (requestHolder.uiViewModel.showMessageSender) Icons.Default.KeyboardArrowUp else Icons.Default.KeyboardArrowDown,
+ sideIcon = Icons.Default.KeyboardArrowDown,
+ iconModifier = Modifier.rotate(a),
onSideIconClick = { requestHolder.toggleMessageSender() },
sidePadding = false
) {
@@ -58,7 +64,7 @@ fun MessageListPage(requestHolder: RequestHolder) {
Column(
modifier = Modifier
.fillMaxWidth()
- .padding(bottom = 16.dp)
+ .padding(bottom = 20.dp)
.padding(horizontal = ConstValues.MainPageSidePadding)
) {
@@ -97,6 +103,7 @@ fun MessageListPage(requestHolder: RequestHolder) {
items = messageList,
key = { item: MessageEntity -> item.id }) { message: MessageEntity ->
SwipeToDismissItem(
+ requestHolder = requestHolder,
onAction = {
requestHolder.message.messageRemove(message.toMessage(), onDone = {
requestHolder.messageViewModel.delete(message)
diff --git a/android/app/src/main/java/com/pushdeer/os/ui/compose/page/main/SettingPage.kt b/android/app/src/main/java/com/pushdeer/os/ui/compose/page/main/SettingPage.kt
index 4aba2bc..427b6ef 100644
--- a/android/app/src/main/java/com/pushdeer/os/ui/compose/page/main/SettingPage.kt
+++ b/android/app/src/main/java/com/pushdeer/os/ui/compose/page/main/SettingPage.kt
@@ -3,16 +3,32 @@ package com.pushdeer.os.ui.compose.page.main
import android.content.Intent
import android.net.Uri
import android.util.Log
-import androidx.compose.foundation.layout.fillMaxSize
+import androidx.annotation.DrawableRes
+import androidx.compose.animation.*
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.Card
import androidx.compose.material.ExperimentalMaterialApi
-import androidx.compose.runtime.Composable
+import androidx.compose.material.Icon
+import androidx.compose.runtime.*
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
import com.pushdeer.os.R
+import com.pushdeer.os.data.api.data.response.UserInfo
import com.pushdeer.os.holder.RequestHolder
import com.pushdeer.os.ui.compose.componment.SettingItem
import com.pushdeer.os.ui.navigation.Page
+import com.pushdeer.os.ui.theme.MainBlue
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
@ExperimentalMaterialApi
@Composable
@@ -21,51 +37,123 @@ fun SettingPage(requestHolder: RequestHolder) {
titleStringId = Page.Settings.labelStringId,
showSideIcon = false
) {
+ var showLoginMethod by remember {
+ mutableStateOf(false)
+ }
+
+ LaunchedEffect(Unit) {
+ requestHolder.coroutineScope.launch {
+ delay(300)
+ showLoginMethod = true
+ }
+ }
+
LazyColumn(
modifier = Modifier.fillMaxSize()
) {
item {
-// var newName by remember {
-// mutableStateOf(requestHolder.pushDeerViewModel.userInfo.name)
-// }
- SettingItem(
- text = "${stringResource(id = R.string.main_setting_user_hi)} ${requestHolder.pushDeerViewModel.userInfo.name} !",
- buttonString = stringResource(id = R.string.main_setting_user_logout),
- onItemClick = {
-
-// requestHolder.alert.alert(
-// title = "修改用户名",
-// content = {
-// TextField(
-// value = newName,
-// onValueChange = { newName = it },
-// colors = TextFieldDefaults.textFieldColors(
-// focusedIndicatorColor = Color.Transparent,
-// unfocusedIndicatorColor = Color.Transparent,
-// disabledIndicatorColor = Color.Transparent,
-// errorIndicatorColor = Color.Transparent,
-// )
-// )
-// },
-// onOk = {
-//
-// }
-// )
- }
+ Card(
+ elevation = 5.dp,
+ modifier = Modifier.padding(bottom = 16.dp),
+ shape = RoundedCornerShape(8.dp),
+ border = BorderStroke(1.dp, MainBlue)
) {
- requestHolder.pushDeerViewModel.deviceList.filter { it.device_id == requestHolder.settingStore.thisDeviceId }
- .forEach {
- requestHolder.device.deviceRemove(it)
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ ) {
+ SettingItem(
+ text = "${stringResource(id = R.string.main_setting_user_hi)} ${requestHolder.pushDeerViewModel.userInfo.name} !",
+ buttonString = stringResource(id = R.string.main_setting_user_logout),
+ paddingValues = PaddingValues(bottom = 0.dp),
+ onItemClick = {}
+ ) {
+ requestHolder.pushDeerViewModel.deviceList
+ .filter { it.device_id == requestHolder.settingStore.thisDeviceId }
+ .forEach { requestHolder.device.deviceRemove(it) }
+ requestHolder.settingStore.userToken = ""
+ requestHolder.globalNavController.navigate("login") {
+ requestHolder.globalNavController.popBackStack()
+ requestHolder.pushDeerViewModel.userInfo = UserInfo()
+ }
+ requestHolder.alert.alert(
+ title = R.string.global_alert_title_alert,
+ content = R.string.main_setting_alert_logout,
+ onOk = {}
+ )
+ }
+ AnimatedVisibility(
+ visible = showLoginMethod,
+ enter = fadeIn() + expandVertically(),
+ exit = fadeOut() + shrinkVertically()
+ ) {
+
+ // LoginMethod Row
+ Row(
+ Modifier
+ .fillMaxWidth()
+ .padding(bottom = 6.dp, start = 6.dp, end = 6.dp, top = 8.dp),
+ horizontalArrangement = Arrangement.SpaceEvenly,
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+
+ // wx 登陆按钮
+ Row(
+ horizontalArrangement = Arrangement.SpaceEvenly,
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = Modifier
+ .weight(0.5F)
+ .clickable {
+ if (requestHolder.pushDeerViewModel.userInfo.isWeChatLogin) {
+ requestHolder.alert.alert(
+ title = "Hey",
+ content = "你已经通过 微信账号 成功登陆咯!",
+ onOk = {})
+ } else {
+ requestHolder.alert.alert(
+ title = "绑定或迁移由 微信账号 创建的账号",
+ content = "请注意,如果你将要登陆的 微信账号 已经在此登陆过,其设备列表将会与当前账号合并, PushKey 将会在合并时丢失。",
+ onOk = requestHolder.weChatLogin.login
+ )
+ }
+ }
+ ) {
+ LoginMethod(
+ isLogin = requestHolder.pushDeerViewModel.userInfo.isWeChatLogin,
+ id = R.drawable.ic_wechat_colored
+ )
+
+ }
+
+ // apple 登陆按钮
+ Row(
+ horizontalArrangement = Arrangement.SpaceEvenly,
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = Modifier
+ .weight(0.5F)
+ .clickable {
+ if (requestHolder.pushDeerViewModel.userInfo.isAppleLogin) {
+ requestHolder.alert.alert(
+ title = "Hey",
+ content = "你已经通过 Apple Id 成功登陆咯!",
+ onOk = {})
+ } else {
+ requestHolder.alert.alert(
+ title = "绑定或迁移由 Apple Id 创建的账号",
+ content = "请注意,如果你将要用来登陆 PushDeer 的 Apple Id 已经在此登陆过,其设备列表将会与当前账号合并, PushKey 将会在合并时丢失。",
+ onOk = requestHolder.appleLogin.login
+ )
+ }
+ }
+ ) {
+ LoginMethod(
+ isLogin = requestHolder.pushDeerViewModel.userInfo.isAppleLogin,
+ id = R.drawable.ic_apple_colored
+ )
+ }
+ }
}
- requestHolder.settingStore.userToken = ""
- requestHolder.globalNavController.navigate("login") {
- requestHolder.globalNavController.popBackStack()
}
- requestHolder.alert.alert(
- R.string.global_alert_title_alert,
- R.string.main_setting_alert_logout,
- {}
- )
}
}
// item {
@@ -81,7 +169,7 @@ fun SettingPage(requestHolder: RequestHolder) {
text = stringResource(id = R.string.main_setting_douyoulike),
buttonString = stringResource(id = R.string.main_setting_btn_like)
) {
- val uri = Uri.parse("market://details?id=" + "com.pushdeer.os")
+ val uri = Uri.parse("market://details?id=com.pushdeer.os")
Intent(Intent.ACTION_VIEW, uri).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}.let {
@@ -107,12 +195,43 @@ fun SettingPage(requestHolder: RequestHolder) {
}
}
-//@Composable
-//fun TogglePreferenceItem(label: String) {
-// Row(
-// verticalAlignment = Alignment.CenterVertically,
-// modifier = Modifier.fillMaxSize()
-// ) {
-// Text(text = label)
-// }
-//}
\ No newline at end of file
+@Composable
+fun IconYes() {
+ Icon(
+ painter = painterResource(id = R.drawable.ic_okok2),
+ contentDescription = "",
+ tint = MainBlue,
+ modifier = Modifier.size(20.dp)
+ )
+}
+
+@Composable
+fun IconNo() {
+ Icon(
+ painter = painterResource(id = R.drawable.ic_okok2),
+ contentDescription = "",
+ tint = Color.Gray,
+ modifier = Modifier.size(20.dp)
+ )
+}
+
+@Composable
+fun LoginMethod(isLogin: Boolean, @DrawableRes id: Int) {
+ Row(
+ modifier = Modifier.width(70.dp),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ if (isLogin)
+ IconYes()
+ else
+ IconNo()
+ Image(
+ painter = painterResource(id = id),
+ contentDescription = "",
+ modifier = Modifier
+ .padding(vertical = 12.dp)
+ .size(35.dp),
+ )
+ }
+}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/pushdeer/os/ui/theme/Color.kt b/android/app/src/main/java/com/pushdeer/os/ui/theme/Color.kt
index b55e96a..60288b6 100644
--- a/android/app/src/main/java/com/pushdeer/os/ui/theme/Color.kt
+++ b/android/app/src/main/java/com/pushdeer/os/ui/theme/Color.kt
@@ -9,4 +9,6 @@ val Teal200 = Color(0xFF03DAC5)
val MainBlue = Color(0xFF3B4789)
val MainGreen = Color(0xFF296C05)
-val MainBottomBtn = Color(0xFF8E8E8E)
\ No newline at end of file
+val MainBottomBtn = Color(0xFF8E8E8E)
+val SwipeToDismissRed = Color(0x92FFF2F2)
+val SwipeToDismissGray = Color(0x92B6B6B6)
\ No newline at end of file
diff --git a/android/app/src/main/java/com/pushdeer/os/viewmodel/PushDeerViewModel.kt b/android/app/src/main/java/com/pushdeer/os/viewmodel/PushDeerViewModel.kt
index db6eb02..e2a13a6 100644
--- a/android/app/src/main/java/com/pushdeer/os/viewmodel/PushDeerViewModel.kt
+++ b/android/app/src/main/java/com/pushdeer/os/viewmodel/PushDeerViewModel.kt
@@ -30,25 +30,24 @@ class PushDeerViewModel(
val keyList = mutableStateListOf()
// var messageList = mutableStateListOf()
- suspend fun login(idToken: String = "", onReturn: (String) -> Unit = {}) {
+ suspend fun loginWithApple(idToken: String = "", onReturn: (String) -> Unit = {}) {
withContext(Dispatchers.IO) {
if (token == "" && idToken != "") {
try {
- pushDeerService.loginIdToken(idToken).let {
+ pushDeerService.loginWithAppleIdToken(idToken).let {
it.content?.let { tokenOnly ->
settingStore.userToken = tokenOnly.token
token = tokenOnly.token
- Log.d(TAG, "login: $token")
+ Log.d(TAG, "loginWithApple: $token")
withContext(Dispatchers.Main) {
onReturn.invoke(token)
}
}
}
- logDogRepository.logi("login", "normally", "nothing happened")
+ logDogRepository.logi("loginWithApple", "withAppleId", "nothing happened")
} catch (e: Exception) {
- Log.d(TAG, "login: ${e.localizedMessage}")
- logDogRepository.loge("login", "", e.toString())
- return@withContext
+ Log.d(TAG, "loginWithApple: ${e.localizedMessage}")
+ logDogRepository.loge("loginWithApple", "", e.toString())
}
} else if (token == "" && idToken == "") {
return@withContext
@@ -60,10 +59,50 @@ class PushDeerViewModel(
}
}
+ suspend fun loginWithWeiXin(code:String,onReturn: (String) -> Unit){
+ withContext(Dispatchers.IO){
+ try {
+ pushDeerService.loginWithWeXin(code).let {
+ it.content?.let { tokenOnly ->
+ settingStore.userToken = tokenOnly.token
+ token = tokenOnly.token
+ Log.d(TAG, "loginWithWeiXin: $token")
+ withContext(Dispatchers.Main) {
+ onReturn.invoke(token)
+ }
+ }
+ }
+ logDogRepository.logi("loginWithWeiXin", "withWeiXin", "nothing happened")
+ }catch (e: Exception){
+ Log.e(TAG, "loginWithWeiXin: ${e.localizedMessage}")
+ logDogRepository.loge("loginWithWeiXin", "", e.toString())
+ }
+ }
+ }
+
+ suspend fun userMerge(type:String,tokenorcode:String,onReturn: (String) -> Unit={}){
+ Log.d("WH_", ": token:${token} type:${type} tokenorcode:${tokenorcode}")
+
+ withContext(Dispatchers.IO){
+ try {
+ pushDeerService.userMerge(token,type,tokenorcode).let {
+ Log.d(TAG, "userMerge: $it")
+ withContext(Dispatchers.Main){
+ onReturn("")
+ }
+ }
+ }catch (e: Exception) {
+ Log.e(TAG, "userMerge:e ${e.localizedMessage}")
+ logDogRepository.loge("userMerge", "", e.toString())
+ }
+ }
+ }
+
suspend fun userInfo(onOk: (UserInfo) -> Unit = {}, onFailed: () -> Unit = {}) {
withContext(Dispatchers.IO) {
try {
pushDeerService.userInfo(token).let {
+ Log.d(TAG, "userInfo: ${it.content}")
it.content?.let { ita ->
userInfo = ita
withContext(Dispatchers.Main) {
diff --git a/android/app/src/main/java/com/pushdeer/os/wxapi/WXEntryActivity.kt b/android/app/src/main/java/com/pushdeer/os/wxapi/WXEntryActivity.kt
new file mode 100644
index 0000000..2f80f6d
--- /dev/null
+++ b/android/app/src/main/java/com/pushdeer/os/wxapi/WXEntryActivity.kt
@@ -0,0 +1,69 @@
+package com.pushdeer.os.wxapi
+
+import android.app.Activity
+import android.content.Intent
+import android.os.Bundle
+import android.util.Log
+import android.widget.Toast
+import com.pushdeer.os.App
+import com.tencent.mm.opensdk.modelbase.BaseReq
+import com.tencent.mm.opensdk.modelbase.BaseResp
+import com.tencent.mm.opensdk.modelmsg.SendAuth
+import com.tencent.mm.opensdk.openapi.IWXAPI
+import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler
+
+
+class WXEntryActivity : Activity(), IWXAPIEventHandler {
+
+ companion object {
+ const val CODE_KEY = "code"
+ const val ACTION_RETURN_CODE = "return-code"
+ }
+
+ private val iwxapi: IWXAPI by lazy { (application as App).iwxapi }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ iwxapi.handleIntent(intent, this);
+ }
+
+ // 微信发送的请求
+ override fun onReq(p0: BaseReq?) {
+
+ }
+
+ // 发送到微信请求的响应结果
+ override fun onResp(p0: BaseResp?) {
+ when (p0?.errCode) {
+ BaseResp.ErrCode.ERR_AUTH_DENIED, BaseResp.ErrCode.ERR_USER_CANCEL ->
+// if (RETURN_MSG_TYPE_SHARE === resp.getType()) {
+// Toast.makeText(this, "分享失败", Toast.LENGTH_SHORT).show()
+// } else {
+ Toast.makeText(this, "登录失败", Toast.LENGTH_SHORT).show()
+// }
+ BaseResp.ErrCode.ERR_OK -> when (p0.type) {
+ 1 -> {
+ // login
+ val code: String = (p0 as SendAuth.Resp).code
+ code.let {
+ sendBroadcast(Intent().apply {
+ putExtra(CODE_KEY, code)
+ action = ACTION_RETURN_CODE
+ })
+ Log.d("WH_", "onResp: $code")
+ finish()
+ }
+ }
+// RETURN_MSG_TYPE_LOGIN -> //拿到了微信返回的code,立马再去请求access_token
+// var code
+// : String
+// ?
+// = (resp as SendAuth.Resp).code
+// RETURN_MSG_TYPE_SHARE -> {
+// Toast.makeText(this, "微信分享成功", Toast.LENGTH_SHORT).show()
+// finish()
+// }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable/deer_placeholder.png b/android/app/src/main/res/drawable/deer_placeholder.png
deleted file mode 100644
index ed7df69..0000000
Binary files a/android/app/src/main/res/drawable/deer_placeholder.png and /dev/null differ
diff --git a/android/app/src/main/res/drawable/ic_apple_colored.xml b/android/app/src/main/res/drawable/ic_apple_colored.xml
new file mode 100644
index 0000000..637d32a
--- /dev/null
+++ b/android/app/src/main/res/drawable/ic_apple_colored.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/android/app/src/main/res/drawable/ic_markdown.xml b/android/app/src/main/res/drawable/ic_markdown.xml
deleted file mode 100644
index 054618a..0000000
--- a/android/app/src/main/res/drawable/ic_markdown.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/android/app/src/main/res/drawable/ic_okok2.xml b/android/app/src/main/res/drawable/ic_okok2.xml
new file mode 100644
index 0000000..f54df64
--- /dev/null
+++ b/android/app/src/main/res/drawable/ic_okok2.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/android/app/src/main/res/drawable/ic_wechat_colored.xml b/android/app/src/main/res/drawable/ic_wechat_colored.xml
new file mode 100644
index 0000000..92b1bee
--- /dev/null
+++ b/android/app/src/main/res/drawable/ic_wechat_colored.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
diff --git a/android/app/src/main/res/values-zh/strings.xml b/android/app/src/main/res/values-zh/strings.xml
index 5990b6a..745155c 100644
--- a/android/app/src/main/res/values-zh/strings.xml
+++ b/android/app/src/main/res/values-zh/strings.xml
@@ -29,4 +29,5 @@
喜欢 PushDeer 吗?
喜欢
由于厂商推送设备服务限制,暂时不支持更换为自建 PushDeer 服务器,但仅更换登陆账号并不会影响您的使用。
+ 确定删除?
\ No newline at end of file
diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml
index 06d7b27..b49cbc4 100644
--- a/android/app/src/main/res/values/strings.xml
+++ b/android/app/src/main/res/values/strings.xml
@@ -28,4 +28,5 @@
Do you line PushDeer?
Like
Due to the limitations of the vendor\'s push device service, it is not supported to change to the self-built PushDeer server for the time being, but only changing the login account will not affect your use.
+ Delete?