네, 작성하신 코드의 방향이 맞습니다. 다만 한두가지 수정하시면 더 좋을 것 같은 부분을 말씀드릴게요.
class Presenter(var viewInterface: ViewInterface)
먼저 ViewInterface의 이름을 LoginView, Presenter 는 LoginPresenter와 같이 좀 더 명시적으로 주시면 어떤 역할을 하는 클래스들인지 이름을 보고도 알 수 있을 것 같습니다.
MakeToast -> makeToast
Login -> login
처럼 camelCase로 사용하시는 것이 대부분 사용하는 코틀린의 명명규칙입니다. 클래스이름, 명명 규칙을 먼저 말씀드리는 것은 그만큼 중요하기 때문입니다.
ViewInterface는 실제 구현은 LoginActivity가 되기 때문에 라이프사이클과 필요하다면 Confiruation changes를 고려해주실 수 있다면 더 좋을 것 같습니다. 즉 Configuration change 등으로 인해 ViewInterface는 null이 될 가능성이 있습니다. 따라서 nullable 타입이 되는 것이 더 안전합니다. 따라서 Activity onStart와 viewInterface를 설정해 주고 onStop에서 null로 설정해 주는 것이 더 안전합니다만, 해당 사항이 없다라고 확신이 드시면 그냥 현재대로 사용하셔도 됩니다. 이런 이유로 구글이 ViewModel이란 걸 도입했습니다만, 꼭 사용해야 한다고는 생각하지 않습니다. 프로젝트의 규모, 특성 등등 여러가지가 고려되여야할 부분이기 때문입니다.
그리고 가급적이면 안드로이 플랫폼에 종속적인 Context, Intent같은 클래스는 Presenter에서 사용하지 않는 것이 좋습니다. MVP 패턴이 사랑받는 이유 중의 하나가 Unit test 코드를 작성하기 아주 쉬운 구조를 제공하기 때문인데, 안드로이드에 종속된 코드가 들어가면 Unit test를 작성하기가 어려워 질 뿐더러 경우에 따라서는 lifecycle에 더 영향을 받는 코드가 될 수 있기 때문입니다. 그리고 startActivity같은 네비게이션 관련 코드는 코드의 주체가 뷰에 있는 것이 좀 더 자연스럽습니다. 따라서 아래와 같은 형태를 고려해 보시면 좋을 것 같습니다.
// LoginActivity
class LoginActivity : AppCompatActivity(), View.OnClickListener,ViewInterface {
...
override fun onClick(v: View?) {
when (v?.id) {
R.id.btn_login -> {
presenter.Login(binding.tvEmail.text.toString(),binding.tvPassword.text.toString())
}
R.id.btn_signup -> {
intent = Intent(this, SignupActivity::class.java)
startActivity(intent)
}
}
}
override fun navigateToMain() {
startActivity(Intent(this, MainActivity::class.java))
}
}
// LoginPresenter
fun Login(email: String, password: String, intent: Intent) {
if (email.isEmpty() || password.isEmpty()) {
viewInterface.showMessage("아이디와 비밀번호를 모두 입력해주세요")
return
}
requestLogin(email, password)
}
private val auth by lazy { FirebaseAuth.getInstance()!! }
private fun requestLogin(email: String, password: String) {
auth.signInWithEmailAndPassword(email, password)
.addOnCompleteListener { task ->
if (task.isSuccessful) {
viewInterface.showMessage("로그인 완료")
viewInterface.navigateToMain()
// 또는 위의 두 동작을 합쳐서
// viewInterface.loginSucceeded()
} else {
viewInterface.showMessage("아이디 또는 비밀번호가 틀렸습니다")
// 또는
// viewInterface.loginFailed(task.exception)
}
}
}
만약 네비게이션이 여러개 라면 아래 처럼 enum 이나 seal class를 사용하시면 됩니다.
enum class NavDestination {
LOGIN_TO_MAIN,
}
override fun navigate(destination: NavDestination) {
val intent = when (destination) {
LOGIN_TO_MAIN -> Intent(this, MainActivity::class.java)
}
startActivity(intent)
}