Commit 73dc7111 authored by jiangjiantao's avatar jiangjiantao

dev

parent 15d25b56
...@@ -44,9 +44,11 @@ dependencies { ...@@ -44,9 +44,11 @@ dependencies {
implementation 'androidx.constraintlayout:constraintlayout:2.0.1' implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0' implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0' implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
implementation("com.squareup.okhttp3:okhttp:4.9.3")
implementation("com.squareup.okhttp3:logging-interceptor:3.9.0")
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation 'androidx.annotation:annotation:1.1.0' implementation 'androidx.annotation:annotation:1.1.0'
testImplementation 'junit:junit:4.+' testImplementation 'junit:junit:4.+'
implementation "com.squareup.retrofit2:retrofit:2.9.0"
implementation 'com.squareup.retrofit2:converter-gson:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation('com.squareup.retrofit2:converter-simplexml:2.9.0') { implementation('com.squareup.retrofit2:converter-simplexml:2.9.0') {
exclude group: 'xpp3', module: 'xpp3' exclude group: 'xpp3', module: 'xpp3'
......
...@@ -2,6 +2,10 @@ ...@@ -2,6 +2,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.miya.fastcashier"> package="com.miya.fastcashier">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application <application
android:allowBackup="true" android:allowBackup="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
...@@ -10,15 +14,15 @@ ...@@ -10,15 +14,15 @@
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.MiYaFastCashier"> android:theme="@style/Theme.MiYaFastCashier">
<activity <activity
android:name=".ui.login.ui.login.LoginActivity" android:name=".ui.login.ui.login.LoginActivity">
android:label="@string/title_activity_login">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name=".MainActivity"></activity> <activity android:name=".MainActivity">
</activity>
</application> </application>
</manifest> </manifest>
\ No newline at end of file
package com.miya.fastcashier.beans
import com.google.gson.annotations.SerializedName
data class LoginRequest(@SerializedName("userName") val userName: String,
@SerializedName("password") val password: String,
@SerializedName("serialNo") val serialNo: String)
package com.miya.fastcashier.repository
class LoginRepository {
}
\ No newline at end of file
package com.miya.fastcashier.service
data class BaseResult<T>(val code: String, val msg: String, val data: T)
\ No newline at end of file
package com.miya.fastcashier.service
import com.miya.fastcashier.beans.SelfCashierAccountInfo
import com.miya.fastcashier.beans.LoginRequest;
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.Body
import retrofit2.http.POST
interface LoginService {
@POST("verify/auth/token")
suspend fun login(@Body loginRequestCall: LoginRequest): BaseResult<SelfCashierAccountInfo>
companion object {
private const val BASE_URL = "https://hhmspre.miyapay.com/"
private var service: LoginService? = null
fun getApi(): LoginService {
if (null == service) {
val httpLoggingInterceptor =
HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BASIC }
val client = OkHttpClient.Builder()
.addInterceptor(httpLoggingInterceptor)
.build()
val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
service = retrofit.create(LoginService::class.java)
}
return service!!
}
}
}
\ No newline at end of file
package com.miya.fastcashier.ui.login.ui.login
/**
* User details post authentication that is exposed to the UI
*/
data class LoggedInUserView(
val displayName: String
//... other data fields that may be accessible to the UI
)
\ No newline at end of file
...@@ -8,6 +8,7 @@ import androidx.annotation.StringRes ...@@ -8,6 +8,7 @@ import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import android.text.Editable import android.text.Editable
import android.text.TextWatcher import android.text.TextWatcher
import android.util.Log
import android.view.View import android.view.View
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import android.widget.EditText import android.widget.EditText
...@@ -29,102 +30,23 @@ class LoginActivity : AppCompatActivity() { ...@@ -29,102 +30,23 @@ class LoginActivity : AppCompatActivity() {
val username = binding.username val username = binding.username
val password = binding.password val password = binding.password
val login = binding.login
val loading = binding.loading
// loginViewModel = ViewModelProvider(this, LoginViewModelFactory()) loginViewModel = ViewModelProvider(this)
// .get(LoginViewModel::class.java) .get(LoginViewModel::class.java)
//
// loginViewModel.loginFormState.observe(this@LoginActivity, Observer {
// val loginState = it ?: return@Observer
//
// // disable login button unless both username / password is valid
// login.isEnabled = loginState.isDataValid
//
// if (loginState.usernameError != null) {
// username.error = getString(loginState.usernameError)
// }
// if (loginState.passwordError != null) {
// password.error = getString(loginState.passwordError)
// }
// })
loginViewModel.loginResult.observe(this@LoginActivity, Observer { loginViewModel.loginLiveData.observe(this) { result ->
val loginResult = it ?: return@Observer val selfCashierAccountInfo = result.getOrNull()
if (null == selfCashierAccountInfo) {
loading.visibility = View.GONE Log.e("######","失败")
if (loginResult.error != null) { return@observe
showLoginFailed(loginResult.error)
}
if (loginResult.success != null) {
updateUiWithUser(loginResult.success)
} }
setResult(Activity.RESULT_OK) Log.e("######","成功")
//Complete and destroy login activity once successful
finish()
})
username.afterTextChanged {
loginViewModel.loginDataChanged(
username.text.toString(),
password.text.toString()
)
} }
password.apply { binding.login.setOnClickListener{
afterTextChanged { loginViewModel.login("miyago","123456")
loginViewModel.loginDataChanged(
username.text.toString(),
password.text.toString()
)
}
setOnEditorActionListener { _, actionId, _ ->
when (actionId) {
EditorInfo.IME_ACTION_DONE ->
loginViewModel.login(
username.text.toString(),
password.text.toString()
)
}
false
}
login.setOnClickListener {
loading.visibility = View.VISIBLE
loginViewModel.login(username.text.toString(), password.text.toString())
}
} }
}
private fun updateUiWithUser(model: LoggedInUserView) {
val welcome = getString(R.string.welcome)
val displayName = model.displayName
// TODO : initiate successful logged in experience
Toast.makeText(
applicationContext,
"$welcome $displayName",
Toast.LENGTH_LONG
).show()
}
private fun showLoginFailed(@StringRes errorString: Int) {
Toast.makeText(applicationContext, errorString, Toast.LENGTH_SHORT).show()
} }
} }
/**
* Extension function to simplify setting an afterTextChanged action to EditText components.
*/
fun EditText.afterTextChanged(afterTextChanged: (String) -> Unit) {
this.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(editable: Editable?) {
afterTextChanged.invoke(editable.toString())
}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
})
}
\ No newline at end of file
package com.miya.fastcashier.ui.login.ui.login
/**
* Authentication result : success (user details) or error message.
*/
data class LoginResult(
val success: LoggedInUserView? = null,
val error: Int? = null
)
\ No newline at end of file
...@@ -26,6 +26,7 @@ class MainFragment : Fragment() { ...@@ -26,6 +26,7 @@ class MainFragment : Fragment() {
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProvider(this).get(MainViewModel::class.java) viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
// TODO: Use the ViewModel // TODO: Use the ViewModel
} }
......
...@@ -3,54 +3,30 @@ package com.miya.fastcashier.viewmodel ...@@ -3,54 +3,30 @@ package com.miya.fastcashier.viewmodel
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import android.util.Patterns import androidx.lifecycle.viewModelScope
import com.miya.fastcashier.R import com.miya.fastcashier.beans.LoginRequest
import com.miya.fastcashier.repository.LoginRepository import com.miya.fastcashier.beans.SelfCashierAccountInfo
import com.miya.fastcashier.service.BaseResult
import com.miya.fastcashier.service.LoginService
import kotlinx.coroutines.launch
import java.lang.RuntimeException
import com.miya.fastcashier.ui.login.ui.login.LoggedInUserView class LoginViewModel : ViewModel() {
import com.miya.fastcashier.ui.login.ui.login.LoginResult
val loginLiveData: MutableLiveData<Result<BaseResult<SelfCashierAccountInfo>>> = MutableLiveData()
fun login(userName:String,passWord:String) {
viewModelScope.launch {
val result = try {
// 网络返回成功
Result.success(LoginService.getApi().login(LoginRequest(userName,passWord,"")))
} catch (e: Exception) {
// 网络返回失败
Result.failure(e)
}
// 注意这里是主线程,直接用setValue()即可
loginLiveData.value = result
}
}
class LoginViewModel(private val loginRepository: LoginRepository) : ViewModel() {
//
// private val _loginForm = MutableLiveData<LoginFormState>()
// val loginFormState: LiveData<LoginFormState> = _loginForm
//
// private val _loginResult = MutableLiveData<LoginResult>()
// val loginResult: LiveData<LoginResult> = _loginResult
//
// fun login(username: String, password: String) {
// // can be launched in a separate asynchronous job
//// val result = loginRepository.login(username, password)
////
//// if (result is Result.Success) {
//// _loginResult.value =
//// LoginResult(success = LoggedInUserView(displayName = result.data.displayName))
//// } else {
//// _loginResult.value = LoginResult(error = R.string.login_failed)
//// }
// }
//
// fun loginDataChanged(username: String, password: String) {
// if (!isUserNameValid(username)) {
// _loginForm.value = LoginFormState(usernameError = R.string.invalid_username)
// } else if (!isPasswordValid(password)) {
// _loginForm.value = LoginFormState(passwordError = R.string.invalid_password)
// } else {
// _loginForm.value = LoginFormState(isDataValid = true)
// }
// }
//
// // A placeholder username validation check
// private fun isUserNameValid(username: String): Boolean {
// return if (username.contains('@')) {
// Patterns.EMAIL_ADDRESS.matcher(username).matches()
// } else {
// username.isNotBlank()
// }
// }
//
// // A placeholder password validation check
// private fun isPasswordValid(password: String): Boolean {
// return password.length > 5
// }
} }
\ No newline at end of file
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
android:layout_marginEnd="48dp" android:layout_marginEnd="48dp"
android:layout_marginBottom="64dp" android:layout_marginBottom="64dp"
android:enabled="false" android:enabled="true"
android:text="@string/action_sign_in" android:text="@string/action_sign_in"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment