Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/unit_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
run: ./gradlew testProdDebugUnitTest $CI_GRADLE_ARG_PROPERTIES

- name: Upload reports
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
if: failure()
with:
name: failures
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="${applicationId}" />
</intent-filter>

<!-- Branch URI Scheme -->
<intent-filter>
Expand Down
18 changes: 16 additions & 2 deletions app/src/main/java/org/openedx/app/AppActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package org.openedx.app
import android.content.Intent
import android.content.res.Configuration
import android.graphics.Color
import android.net.Uri
import android.os.Bundle
import android.view.View
import android.view.WindowManager
Expand Down Expand Up @@ -56,6 +57,14 @@ class AppActivity : AppCompatActivity(), InsetHolder, WindowSizeHolder {
private var _insetCutout = 0

private var _windowSize = WindowSize(WindowType.Compact, WindowType.Compact)
private val authCode: String?
get() {
val data = intent?.data
if (data is Uri && data.scheme == BuildConfig.APPLICATION_ID && data.host == "oauth2Callback") {
return data.getQueryParameter("code")
}
return null
}

override fun onSaveInstanceState(outState: Bundle) {
outState.putInt(TOP_INSET, topInset)
Expand Down Expand Up @@ -119,10 +128,15 @@ class AppActivity : AppCompatActivity(), InsetHolder, WindowSizeHolder {
if (savedInstanceState == null) {
when {
corePreferencesManager.user == null -> {
if (viewModel.isLogistrationEnabled) {
val authCode = authCode;
if (viewModel.isLogistrationEnabled && authCode == null) {
addFragment(LogistrationFragment())
} else {
addFragment(SignInFragment())
val bundle = Bundle()
bundle.putString("auth_code", authCode)
val fragment = SignInFragment()
fragment.arguments = bundle
addFragment(fragment)
}
}

Expand Down
32 changes: 5 additions & 27 deletions app/src/main/java/org/openedx/app/MainFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ import org.openedx.core.config.Config
import org.openedx.core.presentation.global.app_upgrade.UpgradeRequiredFragment
import org.openedx.core.presentation.global.viewBinding
import org.openedx.dashboard.presentation.DashboardFragment
import org.openedx.discovery.presentation.DiscoveryNavigator
import org.openedx.discovery.presentation.DiscoveryRouter
import org.openedx.discovery.presentation.program.ProgramFragment
import org.openedx.profile.presentation.profile.ProfileFragment

class MainFragment : Fragment(R.layout.fragment_main) {
Expand Down Expand Up @@ -47,24 +45,14 @@ class MainFragment : Fragment(R.layout.fragment_main) {

binding.bottomNavView.setOnItemSelectedListener {
when (it.itemId) {
R.id.fragmentHome -> {
viewModel.logDiscoveryTabClickedEvent()
binding.viewPager.setCurrentItem(0, false)
}

R.id.fragmentDashboard -> {
viewModel.logMyCoursesTabClickedEvent()
binding.viewPager.setCurrentItem(1, false)
}

R.id.fragmentPrograms -> {
viewModel.logMyProgramsTabClickedEvent()
binding.viewPager.setCurrentItem(2, false)
binding.viewPager.setCurrentItem(0, false)
}

R.id.fragmentProfile -> {
viewModel.logProfileTabClickedEvent()
binding.viewPager.setCurrentItem(3, false)
binding.viewPager.setCurrentItem(1, false)
}
}
true
Expand All @@ -77,9 +65,9 @@ class MainFragment : Fragment(R.layout.fragment_main) {
}

viewLifecycleOwner.lifecycleScope.launch {
viewModel.navigateToDiscovery.collect { shouldNavigateToDiscovery ->
if (shouldNavigateToDiscovery) {
binding.bottomNavView.selectedItemId = R.id.fragmentHome
viewModel.navigateToHome.collect { shouldNavigateToHome ->
if (shouldNavigateToHome) {
binding.bottomNavView.selectedItemId = R.id.fragmentDashboard
}
}
}
Expand All @@ -105,18 +93,8 @@ class MainFragment : Fragment(R.layout.fragment_main) {
binding.viewPager.orientation = ViewPager2.ORIENTATION_HORIZONTAL
binding.viewPager.offscreenPageLimit = 4

val discoveryFragment = DiscoveryNavigator(viewModel.isDiscoveryTypeWebView)
.getDiscoveryFragment()
val programFragment = if (viewModel.isProgramTypeWebView) {
ProgramFragment(true)
} else {
InDevelopmentFragment()
}

adapter = MainNavigationFragmentAdapter(this).apply {
addFragment(discoveryFragment)
addFragment(DashboardFragment())
addFragment(programFragment)
addFragment(ProfileFragment())
}
binding.viewPager.adapter = adapter
Expand Down
8 changes: 4 additions & 4 deletions app/src/main/java/org/openedx/app/MainViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ class MainViewModel(
val isBottomBarEnabled: LiveData<Boolean>
get() = _isBottomBarEnabled

private val _navigateToDiscovery = MutableSharedFlow<Boolean>()
val navigateToDiscovery: SharedFlow<Boolean>
get() = _navigateToDiscovery.asSharedFlow()
private val _navigateToHome = MutableSharedFlow<Boolean>()
val navigateToHome: SharedFlow<Boolean>
get() = _navigateToHome.asSharedFlow()

val isDiscoveryTypeWebView get() = config.getDiscoveryConfig().isViewTypeWebView()

Expand All @@ -37,7 +37,7 @@ class MainViewModel(
super.onCreate(owner)
notifier.notifier.onEach {
if (it is NavigationToDiscovery) {
_navigateToDiscovery.emit(true)
_navigateToHome.emit(true)
}
}.distinctUntilChanged().launchIn(viewModelScope)
}
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/org/openedx/app/di/AppModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import org.openedx.app.system.notifier.AppNotifier
import org.openedx.auth.presentation.AgreementProvider
import org.openedx.auth.presentation.AuthAnalytics
import org.openedx.auth.presentation.AuthRouter
import org.openedx.auth.presentation.sso.BrowserAuthHelper
import org.openedx.auth.presentation.sso.FacebookAuthHelper
import org.openedx.auth.presentation.sso.GoogleAuthHelper
import org.openedx.auth.presentation.sso.MicrosoftAuthHelper
Expand Down Expand Up @@ -180,5 +181,6 @@ val appModule = module {
factory { FacebookAuthHelper() }
factory { GoogleAuthHelper(get()) }
factory { MicrosoftAuthHelper() }
factory { BrowserAuthHelper(get()) }
factory { OAuthHelper(get(), get(), get()) }
}
4 changes: 3 additions & 1 deletion app/src/main/java/org/openedx/app/di/ScreenModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ val screenModule = module {
get(),
get(),
get(),
get(),
)
}

Expand All @@ -92,6 +93,7 @@ val screenModule = module {
get(),
get(),
get(),
get(),
courseId,
infoType,
)
Expand All @@ -115,7 +117,7 @@ val screenModule = module {
viewModel { RestorePasswordViewModel(get(), get(), get(), get()) }

factory { DashboardRepository(get(), get(), get()) }
factory { DashboardInteractor(get()) }
factory { DashboardInteractor(get(), get()) }
viewModel { DashboardViewModel(get(), get(), get(), get(), get(), get(), get()) }

factory { DiscoveryRepository(get(), get(), get()) }
Expand Down
12 changes: 0 additions & 12 deletions app/src/main/res/menu/bottom_view_menu.xml
Original file line number Diff line number Diff line change
@@ -1,24 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

<item
android:id="@+id/fragmentHome"
android:title="@string/app_navigation_discovery"
android:enabled="true"
android:icon="@drawable/app_ic_home"/>

<item
android:id="@+id/fragmentDashboard"
android:title="@string/app_navigation_dashboard"
android:enabled="true"
android:icon="@drawable/app_ic_rows"/>

<item
android:id="@+id/fragmentPrograms"
android:title="@string/app_navigation_programs"
android:enabled="true"
android:icon="@drawable/app_ic_book"/>

<item
android:id="@+id/fragmentProfile"
android:title="@string/app_navigation_profile"
Expand Down
1 change: 1 addition & 0 deletions auth/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ android {
dependencies {
implementation project(path: ':core')

implementation 'androidx.browser:browser:1.7.0'
implementation "androidx.credentials:credentials:1.2.0"
implementation "androidx.credentials:credentials-play-services-auth:1.2.0"
implementation "com.facebook.android:facebook-login:16.2.0"
Expand Down
11 changes: 11 additions & 0 deletions auth/src/main/java/org/openedx/auth/data/api/AuthApi.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@ interface AuthApi {
@Field("asymmetric_jwt") isAsymmetricJwt: Boolean = true,
): AuthResponse

@FormUrlEncoded
@POST(ApiConstants.URL_ACCESS_TOKEN)
suspend fun getAccessTokenFromCode(
@Field("grant_type") grantType: String,
@Field("client_id") clientId: String,
@Field("code") code: String,
@Field("redirect_uri") redirectUri: String,
@Field("token_type") tokenType: String,
@Field("asymmetric_jwt") isAsymmetricJwt: Boolean = true,
): AuthResponse

@FormUrlEncoded
@POST(ApiConstants.URL_ACCESS_TOKEN)
fun refreshAccessToken(
Expand Down
1 change: 1 addition & 0 deletions auth/src/main/java/org/openedx/auth/data/model/AuthType.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ enum class AuthType(val postfix: String, val methodName: String) {
GOOGLE(ApiConstants.AUTH_TYPE_GOOGLE, "Google"),
FACEBOOK(ApiConstants.AUTH_TYPE_FB, "Facebook"),
MICROSOFT(ApiConstants.AUTH_TYPE_MICROSOFT, "Microsoft"),
BROWSER(ApiConstants.AUTH_TYPE_BROWSER, "Browser")
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@ class AuthRepository(
.processAuthResponse()
}

suspend fun browserAuthCodeLogin(code: String) {
api.getAccessTokenFromCode(
grantType = ApiConstants.GRANT_TYPE_CODE,
clientId = config.getOAuthClientId(),
code = code,
redirectUri = "${config.getApplicationID()}://oauth2Callback",
tokenType = config.getAccessTokenType(),
).mapToDomain().processAuthResponse()
}

suspend fun getRegistrationFields(): List<RegistrationField> {
return api.getRegistrationFields().fields?.map { it.mapToDomain() } ?: emptyList()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ class AuthInteractor(private val repository: AuthRepository) {
repository.socialLogin(token, authType)
}

suspend fun loginAuthCode(authCode: String) {
repository.browserAuthCodeLogin(authCode)
}

suspend fun getRegistrationFields(): List<RegistrationField> {
return repository.getRegistrationFields()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import org.openedx.core.ui.theme.OpenEdXTheme
import org.openedx.core.ui.theme.appColors
import org.openedx.core.ui.theme.appTypography
import org.openedx.core.ui.theme.compose.LogistrationLogoView
import org.openedx.core.utils.UrlUtils

class LogistrationFragment : Fragment() {

Expand All @@ -66,14 +67,28 @@ class LogistrationFragment : Fragment() {
OpenEdXTheme {
LogistrationScreen(
onSignInClick = {
viewModel.navigateToSignIn(parentFragmentManager)
if(viewModel.isBrowserLoginEnabled) {
viewModel.signInBrowser(requireActivity())
} else {
viewModel.navigateToSignIn(parentFragmentManager)
}

},
onRegisterClick = {
viewModel.navigateToSignUp(parentFragmentManager)
if (viewModel.isBrowserRegistrationEnabled) {
UrlUtils.openInBrowser(
activity = context,
apiHostUrl = viewModel.apiHostUrl,
url = "/register",
)
} else {
viewModel.navigateToSignUp(parentFragmentManager)
}
},
onSearchClick = { querySearch ->
viewModel.navigateToDiscovery(parentFragmentManager, querySearch)
}
},
isRegistrationEnabled = viewModel.isRegistrationEnabled
)
}
}
Expand All @@ -97,6 +112,7 @@ private fun LogistrationScreen(
onSearchClick: (String) -> Unit,
onRegisterClick: () -> Unit,
onSignInClick: () -> Unit,
isRegistrationEnabled: Boolean,
) {

var textFieldValue by rememberSaveable(stateSaver = TextFieldValue.Saver) {
Expand Down Expand Up @@ -182,7 +198,11 @@ private fun LogistrationScreen(

Spacer(modifier = Modifier.weight(1f))

AuthButtonsPanel(onRegisterClick = onRegisterClick, onSignInClick = onSignInClick)
AuthButtonsPanel(
onRegisterClick = onRegisterClick,
onSignInClick = onSignInClick,
showRegisterButton = isRegistrationEnabled
)
}
}
}
Expand All @@ -198,7 +218,24 @@ private fun LogistrationPreview() {
LogistrationScreen(
onSearchClick = {},
onSignInClick = {},
onRegisterClick = {}
onRegisterClick = {},
isRegistrationEnabled = true,
)
}
}

@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Preview(name = "NEXUS_9_Light", device = Devices.NEXUS_9, uiMode = Configuration.UI_MODE_NIGHT_NO)
@Preview(name = "NEXUS_9_Night", device = Devices.NEXUS_9, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun LogistrationRegistrationDisabledPreview() {
OpenEdXTheme {
LogistrationScreen(
onSearchClick = {},
onSignInClick = {},
onRegisterClick = {},
isRegistrationEnabled = false,
)
}
}
Loading
Loading