Google/Facebook Sign In in MVVM












6















I'm using MVVM structure with Data Binding in my project. Things get weird when it comes to GG/FB Sign In, because they need Context



googleApiClient = new GoogleApiClient.Builder(context)
.enableAutoManage(this, this)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(googleApiClient);
startActivityForResult(signInIntent, GOOGLE_AUTH);


GoogleApiClient needs Context so I can't pass it to ViewModel, which receives DataBinding events.



class LoginViewModel(
dataManager: DataManager,
schedulerProvider: SchedulerProvider
) : BaseViewModel<LoginNavigator>(dataManager, schedulerProvider) {

fun loginGoogle(){
setIsLoading(true)
//No idea what to write in here
}
}


Is there any way to use Gg/FB Sign In with MVVM structure ? Or I just have to do the original way (do everything in Activity) ?










share|improve this question



























    6















    I'm using MVVM structure with Data Binding in my project. Things get weird when it comes to GG/FB Sign In, because they need Context



    googleApiClient = new GoogleApiClient.Builder(context)
    .enableAutoManage(this, this)
    .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
    .build();
    Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(googleApiClient);
    startActivityForResult(signInIntent, GOOGLE_AUTH);


    GoogleApiClient needs Context so I can't pass it to ViewModel, which receives DataBinding events.



    class LoginViewModel(
    dataManager: DataManager,
    schedulerProvider: SchedulerProvider
    ) : BaseViewModel<LoginNavigator>(dataManager, schedulerProvider) {

    fun loginGoogle(){
    setIsLoading(true)
    //No idea what to write in here
    }
    }


    Is there any way to use Gg/FB Sign In with MVVM structure ? Or I just have to do the original way (do everything in Activity) ?










    share|improve this question

























      6












      6








      6


      1






      I'm using MVVM structure with Data Binding in my project. Things get weird when it comes to GG/FB Sign In, because they need Context



      googleApiClient = new GoogleApiClient.Builder(context)
      .enableAutoManage(this, this)
      .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
      .build();
      Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(googleApiClient);
      startActivityForResult(signInIntent, GOOGLE_AUTH);


      GoogleApiClient needs Context so I can't pass it to ViewModel, which receives DataBinding events.



      class LoginViewModel(
      dataManager: DataManager,
      schedulerProvider: SchedulerProvider
      ) : BaseViewModel<LoginNavigator>(dataManager, schedulerProvider) {

      fun loginGoogle(){
      setIsLoading(true)
      //No idea what to write in here
      }
      }


      Is there any way to use Gg/FB Sign In with MVVM structure ? Or I just have to do the original way (do everything in Activity) ?










      share|improve this question














      I'm using MVVM structure with Data Binding in my project. Things get weird when it comes to GG/FB Sign In, because they need Context



      googleApiClient = new GoogleApiClient.Builder(context)
      .enableAutoManage(this, this)
      .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
      .build();
      Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(googleApiClient);
      startActivityForResult(signInIntent, GOOGLE_AUTH);


      GoogleApiClient needs Context so I can't pass it to ViewModel, which receives DataBinding events.



      class LoginViewModel(
      dataManager: DataManager,
      schedulerProvider: SchedulerProvider
      ) : BaseViewModel<LoginNavigator>(dataManager, schedulerProvider) {

      fun loginGoogle(){
      setIsLoading(true)
      //No idea what to write in here
      }
      }


      Is there any way to use Gg/FB Sign In with MVVM structure ? Or I just have to do the original way (do everything in Activity) ?







      android mvvm kotlin google-signin






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Sep 12 '18 at 3:20









      Chris MaverickChris Maverick

      3781316




      3781316
























          1 Answer
          1






          active

          oldest

          votes


















          2














          It is very simple thanks to @Erik Browne and Kotlin’s Function literals with receiver



          Create SingleLiveEvent



          Create LiveMessageEvent



          class LiveMessageEvent<T> : SingleLiveEvent<(T.() -> Unit)?>() {

          fun setEventReceiver(owner: LifecycleOwner, receiver: T) {
          observe(owner, Observer { event ->
          if ( event != null ) {
          receiver.event()
          }
          })
          }

          fun sendEvent(event: (T.() -> Unit)?) {
          value = event
          }
          }


          Create interface



          interface ActivityNavigation {
          fun startActivityForResult(intent: Intent?, requestCode: Int)
          }


          ** Now it's time to implement! **



          In your LoginViewModel



          const val GOOGLE_SIGN_IN : Int = 9001

          class LoginViewModel @Inject constructor(
          private val loginRepository: LoginRepository,
          private val googleSignInClient: GoogleSignInClient
          ): ViewModel() {

          val startActivityForResultEvent = LiveMessageEvent<ActivityNavigation>()
          ..

          //Called on google login button click
          fun googleSignUp() {
          val signInIntent = googleSignInClient.signInIntent
          startActivityForResultEvent.sendEvent { startActivityForResult(signInIntent, GOOGLE_SIGN_IN) }
          }

          //Called from Activity receving result
          fun onResultFromActivity(requestCode: Int, resultCode: Int, data: Intent?) {
          when(requestCode) {
          GOOGLE_SIGN_IN -> {
          val task = GoogleSignIn.getSignedInAccountFromIntent(data)
          googleSignInComplete(task)
          }
          ..
          }
          }

          private fun googleSignInComplete(completedTask: Task<GoogleSignInAccount>) {
          try {
          val account = completedTask.getResult(ApiException::class.java)
          account?.apply {
          // .. Store user details
          emitUiState(
          showSuccess = Event(R.string.login_successful)
          )
          }
          }catch (e: ApiException) {
          emitUiState(
          showError = Event(R.string.login_failed)
          )
          }
          }



          In your LoginActivty



          //Called from onCreate once the ViewModel is initialized.
          private fun subscribeUi() {
          //this sets the LifeCycler owner and receiver
          viewModel.startActivityForResultEvent.setEventReceiver(this, this)
          ..
          }

          public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
          viewModel.onResultFromActivity(requestCode,resultCode,data)
          super.onActivityResult(requestCode, resultCode, data)
          }


          # Following this approach ensures LoginViewModel acts a link between the view(LoginActivity) and model(GoogleSignInClient) and view is only responsible for displaying the UI events.






          share|improve this answer

























            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52287013%2fgoogle-facebook-sign-in-in-mvvm%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            2














            It is very simple thanks to @Erik Browne and Kotlin’s Function literals with receiver



            Create SingleLiveEvent



            Create LiveMessageEvent



            class LiveMessageEvent<T> : SingleLiveEvent<(T.() -> Unit)?>() {

            fun setEventReceiver(owner: LifecycleOwner, receiver: T) {
            observe(owner, Observer { event ->
            if ( event != null ) {
            receiver.event()
            }
            })
            }

            fun sendEvent(event: (T.() -> Unit)?) {
            value = event
            }
            }


            Create interface



            interface ActivityNavigation {
            fun startActivityForResult(intent: Intent?, requestCode: Int)
            }


            ** Now it's time to implement! **



            In your LoginViewModel



            const val GOOGLE_SIGN_IN : Int = 9001

            class LoginViewModel @Inject constructor(
            private val loginRepository: LoginRepository,
            private val googleSignInClient: GoogleSignInClient
            ): ViewModel() {

            val startActivityForResultEvent = LiveMessageEvent<ActivityNavigation>()
            ..

            //Called on google login button click
            fun googleSignUp() {
            val signInIntent = googleSignInClient.signInIntent
            startActivityForResultEvent.sendEvent { startActivityForResult(signInIntent, GOOGLE_SIGN_IN) }
            }

            //Called from Activity receving result
            fun onResultFromActivity(requestCode: Int, resultCode: Int, data: Intent?) {
            when(requestCode) {
            GOOGLE_SIGN_IN -> {
            val task = GoogleSignIn.getSignedInAccountFromIntent(data)
            googleSignInComplete(task)
            }
            ..
            }
            }

            private fun googleSignInComplete(completedTask: Task<GoogleSignInAccount>) {
            try {
            val account = completedTask.getResult(ApiException::class.java)
            account?.apply {
            // .. Store user details
            emitUiState(
            showSuccess = Event(R.string.login_successful)
            )
            }
            }catch (e: ApiException) {
            emitUiState(
            showError = Event(R.string.login_failed)
            )
            }
            }



            In your LoginActivty



            //Called from onCreate once the ViewModel is initialized.
            private fun subscribeUi() {
            //this sets the LifeCycler owner and receiver
            viewModel.startActivityForResultEvent.setEventReceiver(this, this)
            ..
            }

            public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
            viewModel.onResultFromActivity(requestCode,resultCode,data)
            super.onActivityResult(requestCode, resultCode, data)
            }


            # Following this approach ensures LoginViewModel acts a link between the view(LoginActivity) and model(GoogleSignInClient) and view is only responsible for displaying the UI events.






            share|improve this answer






























              2














              It is very simple thanks to @Erik Browne and Kotlin’s Function literals with receiver



              Create SingleLiveEvent



              Create LiveMessageEvent



              class LiveMessageEvent<T> : SingleLiveEvent<(T.() -> Unit)?>() {

              fun setEventReceiver(owner: LifecycleOwner, receiver: T) {
              observe(owner, Observer { event ->
              if ( event != null ) {
              receiver.event()
              }
              })
              }

              fun sendEvent(event: (T.() -> Unit)?) {
              value = event
              }
              }


              Create interface



              interface ActivityNavigation {
              fun startActivityForResult(intent: Intent?, requestCode: Int)
              }


              ** Now it's time to implement! **



              In your LoginViewModel



              const val GOOGLE_SIGN_IN : Int = 9001

              class LoginViewModel @Inject constructor(
              private val loginRepository: LoginRepository,
              private val googleSignInClient: GoogleSignInClient
              ): ViewModel() {

              val startActivityForResultEvent = LiveMessageEvent<ActivityNavigation>()
              ..

              //Called on google login button click
              fun googleSignUp() {
              val signInIntent = googleSignInClient.signInIntent
              startActivityForResultEvent.sendEvent { startActivityForResult(signInIntent, GOOGLE_SIGN_IN) }
              }

              //Called from Activity receving result
              fun onResultFromActivity(requestCode: Int, resultCode: Int, data: Intent?) {
              when(requestCode) {
              GOOGLE_SIGN_IN -> {
              val task = GoogleSignIn.getSignedInAccountFromIntent(data)
              googleSignInComplete(task)
              }
              ..
              }
              }

              private fun googleSignInComplete(completedTask: Task<GoogleSignInAccount>) {
              try {
              val account = completedTask.getResult(ApiException::class.java)
              account?.apply {
              // .. Store user details
              emitUiState(
              showSuccess = Event(R.string.login_successful)
              )
              }
              }catch (e: ApiException) {
              emitUiState(
              showError = Event(R.string.login_failed)
              )
              }
              }



              In your LoginActivty



              //Called from onCreate once the ViewModel is initialized.
              private fun subscribeUi() {
              //this sets the LifeCycler owner and receiver
              viewModel.startActivityForResultEvent.setEventReceiver(this, this)
              ..
              }

              public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
              viewModel.onResultFromActivity(requestCode,resultCode,data)
              super.onActivityResult(requestCode, resultCode, data)
              }


              # Following this approach ensures LoginViewModel acts a link between the view(LoginActivity) and model(GoogleSignInClient) and view is only responsible for displaying the UI events.






              share|improve this answer




























                2












                2








                2







                It is very simple thanks to @Erik Browne and Kotlin’s Function literals with receiver



                Create SingleLiveEvent



                Create LiveMessageEvent



                class LiveMessageEvent<T> : SingleLiveEvent<(T.() -> Unit)?>() {

                fun setEventReceiver(owner: LifecycleOwner, receiver: T) {
                observe(owner, Observer { event ->
                if ( event != null ) {
                receiver.event()
                }
                })
                }

                fun sendEvent(event: (T.() -> Unit)?) {
                value = event
                }
                }


                Create interface



                interface ActivityNavigation {
                fun startActivityForResult(intent: Intent?, requestCode: Int)
                }


                ** Now it's time to implement! **



                In your LoginViewModel



                const val GOOGLE_SIGN_IN : Int = 9001

                class LoginViewModel @Inject constructor(
                private val loginRepository: LoginRepository,
                private val googleSignInClient: GoogleSignInClient
                ): ViewModel() {

                val startActivityForResultEvent = LiveMessageEvent<ActivityNavigation>()
                ..

                //Called on google login button click
                fun googleSignUp() {
                val signInIntent = googleSignInClient.signInIntent
                startActivityForResultEvent.sendEvent { startActivityForResult(signInIntent, GOOGLE_SIGN_IN) }
                }

                //Called from Activity receving result
                fun onResultFromActivity(requestCode: Int, resultCode: Int, data: Intent?) {
                when(requestCode) {
                GOOGLE_SIGN_IN -> {
                val task = GoogleSignIn.getSignedInAccountFromIntent(data)
                googleSignInComplete(task)
                }
                ..
                }
                }

                private fun googleSignInComplete(completedTask: Task<GoogleSignInAccount>) {
                try {
                val account = completedTask.getResult(ApiException::class.java)
                account?.apply {
                // .. Store user details
                emitUiState(
                showSuccess = Event(R.string.login_successful)
                )
                }
                }catch (e: ApiException) {
                emitUiState(
                showError = Event(R.string.login_failed)
                )
                }
                }



                In your LoginActivty



                //Called from onCreate once the ViewModel is initialized.
                private fun subscribeUi() {
                //this sets the LifeCycler owner and receiver
                viewModel.startActivityForResultEvent.setEventReceiver(this, this)
                ..
                }

                public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
                viewModel.onResultFromActivity(requestCode,resultCode,data)
                super.onActivityResult(requestCode, resultCode, data)
                }


                # Following this approach ensures LoginViewModel acts a link between the view(LoginActivity) and model(GoogleSignInClient) and view is only responsible for displaying the UI events.






                share|improve this answer















                It is very simple thanks to @Erik Browne and Kotlin’s Function literals with receiver



                Create SingleLiveEvent



                Create LiveMessageEvent



                class LiveMessageEvent<T> : SingleLiveEvent<(T.() -> Unit)?>() {

                fun setEventReceiver(owner: LifecycleOwner, receiver: T) {
                observe(owner, Observer { event ->
                if ( event != null ) {
                receiver.event()
                }
                })
                }

                fun sendEvent(event: (T.() -> Unit)?) {
                value = event
                }
                }


                Create interface



                interface ActivityNavigation {
                fun startActivityForResult(intent: Intent?, requestCode: Int)
                }


                ** Now it's time to implement! **



                In your LoginViewModel



                const val GOOGLE_SIGN_IN : Int = 9001

                class LoginViewModel @Inject constructor(
                private val loginRepository: LoginRepository,
                private val googleSignInClient: GoogleSignInClient
                ): ViewModel() {

                val startActivityForResultEvent = LiveMessageEvent<ActivityNavigation>()
                ..

                //Called on google login button click
                fun googleSignUp() {
                val signInIntent = googleSignInClient.signInIntent
                startActivityForResultEvent.sendEvent { startActivityForResult(signInIntent, GOOGLE_SIGN_IN) }
                }

                //Called from Activity receving result
                fun onResultFromActivity(requestCode: Int, resultCode: Int, data: Intent?) {
                when(requestCode) {
                GOOGLE_SIGN_IN -> {
                val task = GoogleSignIn.getSignedInAccountFromIntent(data)
                googleSignInComplete(task)
                }
                ..
                }
                }

                private fun googleSignInComplete(completedTask: Task<GoogleSignInAccount>) {
                try {
                val account = completedTask.getResult(ApiException::class.java)
                account?.apply {
                // .. Store user details
                emitUiState(
                showSuccess = Event(R.string.login_successful)
                )
                }
                }catch (e: ApiException) {
                emitUiState(
                showError = Event(R.string.login_failed)
                )
                }
                }



                In your LoginActivty



                //Called from onCreate once the ViewModel is initialized.
                private fun subscribeUi() {
                //this sets the LifeCycler owner and receiver
                viewModel.startActivityForResultEvent.setEventReceiver(this, this)
                ..
                }

                public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
                viewModel.onResultFromActivity(requestCode,resultCode,data)
                super.onActivityResult(requestCode, resultCode, data)
                }


                # Following this approach ensures LoginViewModel acts a link between the view(LoginActivity) and model(GoogleSignInClient) and view is only responsible for displaying the UI events.







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Jan 21 at 5:30

























                answered Jan 20 at 9:45









                Suyash ChavanSuyash Chavan

                3098




                3098
































                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52287013%2fgoogle-facebook-sign-in-in-mvvm%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Liquibase includeAll doesn't find base path

                    How to use setInterval in EJS file?

                    Petrus Granier-Deferre