Skip to content

Commit 4d36310

Browse files
Merge pull request #314 from openedx/develop
Develop to main v1.5.1
2 parents bccf5ed + 4d782ee commit 4d36310

File tree

109 files changed

+4983
-3369
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

109 files changed

+4983
-3369
lines changed

.github/workflows/unit_tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ jobs:
3939
- name: Generate mock files
4040
run: ./gradlew generateMockedRawFile
4141
- name: Run unit tests
42-
run: ./gradlew testProdReleaseUnitTest $CI_GRADLE_ARG_PROPERTIES
42+
run: ./gradlew testProdDebugUnitTest $CI_GRADLE_ARG_PROPERTIES
4343

4444
- name: Upload reports
4545
uses: actions/upload-artifact@v3

Documentation/ConfigurationManagement.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ MICROSOFT:
6161
CLIENT_ID: 'microsoftClientID'
6262
```
6363
64-
Also, all envirenment folders contain a `file_mappings.yaml` file that points to the config files to be parsed.
64+
Also, all environment folders contain a `file_mappings.yaml` file that points to the config files to be parsed.
6565

6666
By modifying `file_mappings.yaml`, you can achieve splitting of the base `config.yaml` or add additional configuration files.
6767

@@ -81,16 +81,14 @@ android:
8181
- **Microsoft:** Sign in and Sign up via Microsoft
8282
- **Facebook:** Sign in and Sign up via Facebook
8383
- **Branch:** Deeplinks
84-
- **Braze:** Could Messaging
84+
- **Braze:** Cloud Messaging
8585
- **SegmentIO:** Analytics
8686

8787
## Available Feature Flags
8888
- **PRE_LOGIN_EXPERIENCE_ENABLED:** Enables the pre login courses discovery experience.
8989
- **WHATS_NEW_ENABLED:** Enables the "What's New" feature to present the latest changes to the user.
9090
- **SOCIAL_AUTH_ENABLED:** Enables SSO buttons on the SignIn and SignUp screens.
9191
- **COURSE_NESTED_LIST_ENABLED:** Enables an alternative visual representation for the course structure.
92-
- **COURSE_BANNER_ENABLED:** Enables the display of the course image on the Course Home screen.
93-
- **COURSE_TOP_TAB_BAR_ENABLED:** Enables an alternative navigation on the Course Home screen.
9492
- **COURSE_UNIT_PROGRESS_ENABLED:** Enables the display of the unit progress within the courseware.
9593

9694
## Future Support

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Modern vision of the mobile application for the Open edX platform from Raccoon G
1414

1515
3. Choose ``openedx-app-android``.
1616

17-
4. Configure `config_settings.yaml` inside `default_config` and `config.yaml` inside sub direcroties to point to your Open edX configuration. [Configuration Docuementation](./Documentation/ConfigurationManagement.md)
17+
4. Configure `config_settings.yaml` inside `default_config` and `config.yaml` inside sub directories to point to your Open edX configuration. [Configuration Documentation](./Documentation/ConfigurationManagement.md)
1818

1919
5. Select the build variant ``develop``, ``stage``, or ``prod``.
2020

app/src/main/java/org/openedx/app/AppRouter.kt

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,13 @@ import org.openedx.discussion.presentation.threads.DiscussionAddThreadFragment
4343
import org.openedx.discussion.presentation.threads.DiscussionThreadsFragment
4444
import org.openedx.profile.domain.model.Account
4545
import org.openedx.profile.presentation.ProfileRouter
46-
import org.openedx.profile.presentation.anothers_account.AnothersProfileFragment
46+
import org.openedx.profile.presentation.anothersaccount.AnothersProfileFragment
4747
import org.openedx.profile.presentation.delete.DeleteProfileFragment
4848
import org.openedx.profile.presentation.edit.EditProfileFragment
49+
import org.openedx.profile.presentation.manageaccount.ManageAccountFragment
4950
import org.openedx.profile.presentation.profile.ProfileFragment
50-
import org.openedx.profile.presentation.settings.video.VideoSettingsFragment
51+
import org.openedx.profile.presentation.settings.SettingsFragment
52+
import org.openedx.profile.presentation.video.VideoSettingsFragment
5153
import org.openedx.whatsnew.WhatsNewRouter
5254
import org.openedx.whatsnew.presentation.whatsnew.WhatsNewFragment
5355

@@ -328,22 +330,14 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di
328330
replaceFragmentWithBackStack(fm, EditProfileFragment.newInstance(account))
329331
}
330332

331-
override fun navigateToVideoSettings(fm: FragmentManager) {
332-
replaceFragmentWithBackStack(fm, VideoSettingsFragment())
333-
}
334-
335-
override fun navigateToVideoQuality(fm: FragmentManager, videoQualityType: VideoQualityType) {
336-
replaceFragmentWithBackStack(fm, VideoQualityFragment.newInstance(videoQualityType.name))
337-
}
338-
339333
override fun navigateToDeleteAccount(fm: FragmentManager) {
340334
replaceFragmentWithBackStack(fm, DeleteProfileFragment())
341335
}
342336

343-
override fun navigateToWebContent(fm: FragmentManager, title: String, url: String) {
337+
override fun navigateToSettings(fm: FragmentManager) {
344338
replaceFragmentWithBackStack(
345339
fm,
346-
WebContentFragment.newInstance(title = title, url = url)
340+
SettingsFragment()
347341
)
348342
}
349343

@@ -357,6 +351,25 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di
357351
}
358352
}
359353
}
354+
355+
override fun navigateToVideoSettings(fm: FragmentManager) {
356+
replaceFragmentWithBackStack(fm, VideoSettingsFragment())
357+
}
358+
359+
override fun navigateToVideoQuality(fm: FragmentManager, videoQualityType: VideoQualityType) {
360+
replaceFragmentWithBackStack(fm, VideoQualityFragment.newInstance(videoQualityType.name))
361+
}
362+
363+
override fun navigateToWebContent(fm: FragmentManager, title: String, url: String) {
364+
replaceFragmentWithBackStack(
365+
fm,
366+
WebContentFragment.newInstance(title = title, url = url)
367+
)
368+
}
369+
370+
override fun navigateToManageAccount(fm: FragmentManager) {
371+
replaceFragmentWithBackStack(fm, ManageAccountFragment())
372+
}
360373
//endregion
361374

362375
private fun replaceFragmentWithBackStack(fm: FragmentManager, fragment: Fragment) {
@@ -384,4 +397,5 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di
384397
.replace(R.id.container, ProfileFragment())
385398
.commit()
386399
}
400+
//endregion
387401
}

app/src/main/java/org/openedx/app/di/AppModule.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import org.openedx.auth.presentation.sso.FacebookAuthHelper
2525
import org.openedx.auth.presentation.sso.GoogleAuthHelper
2626
import org.openedx.auth.presentation.sso.MicrosoftAuthHelper
2727
import org.openedx.auth.presentation.sso.OAuthHelper
28+
import org.openedx.core.ImageProcessor
2829
import org.openedx.core.config.Config
2930
import org.openedx.core.data.model.CourseEnrollments
3031
import org.openedx.core.data.storage.CorePreferences
@@ -81,6 +82,8 @@ val appModule = module {
8182
single { ReviewManagerFactory.create(get()) }
8283
single { CalendarManager(get(), get(), get()) }
8384

85+
single { ImageProcessor(get()) }
86+
8487
single<Gson> {
8588
GsonBuilder()
8689
.registerTypeAdapter(CourseEnrollments::class.java, CourseEnrollments.Deserializer())

app/src/main/java/org/openedx/app/di/ScreenModule.kt

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,13 @@ import org.openedx.discussion.presentation.topics.DiscussionTopicsViewModel
5252
import org.openedx.profile.data.repository.ProfileRepository
5353
import org.openedx.profile.domain.interactor.ProfileInteractor
5454
import org.openedx.profile.domain.model.Account
55-
import org.openedx.profile.presentation.anothers_account.AnothersProfileViewModel
55+
import org.openedx.profile.presentation.anothersaccount.AnothersProfileViewModel
5656
import org.openedx.profile.presentation.delete.DeleteProfileViewModel
5757
import org.openedx.profile.presentation.edit.EditProfileViewModel
58+
import org.openedx.profile.presentation.manageaccount.ManageAccountViewModel
5859
import org.openedx.profile.presentation.profile.ProfileViewModel
59-
import org.openedx.profile.presentation.settings.video.VideoSettingsViewModel
60+
import org.openedx.profile.presentation.settings.SettingsViewModel
61+
import org.openedx.profile.presentation.video.VideoSettingsViewModel
6062
import org.openedx.whatsnew.presentation.whatsnew.WhatsNewViewModel
6163

6264
val screenModule = module {
@@ -134,24 +136,20 @@ val screenModule = module {
134136
factory { ProfileInteractor(get()) }
135137
viewModel {
136138
ProfileViewModel(
137-
appData = get(),
138-
config = get(),
139139
interactor = get(),
140140
resourceManager = get(),
141141
notifier = get(),
142-
dispatcher = get(named("IODispatcher")),
143-
cookieManager = get(),
144-
workerController = get(),
145142
analytics = get(),
146-
appUpgradeNotifier = get(),
147-
router = get(),
143+
profileRouter = get(),
148144
)
149145
}
150146
viewModel { (account: Account) -> EditProfileViewModel(get(), get(), get(), get(), account) }
151147
viewModel { VideoSettingsViewModel(get(), get(), get(), get()) }
152148
viewModel { (qualityType: String) -> VideoQualityViewModel(qualityType, get(), get(), get()) }
153149
viewModel { DeleteProfileViewModel(get(), get(), get(), get(), get()) }
154150
viewModel { (username: String) -> AnothersProfileViewModel(get(), get(), username) }
151+
viewModel { SettingsViewModel(get(), get(), get(), get(), get(), get(), get(), get(), get(), get()) }
152+
viewModel { ManageAccountViewModel(get(), get(), get(), get(), get()) }
155153

156154
single { CourseRepository(get(), get(), get(), get()) }
157155
factory { CourseInteractor(get()) }
@@ -195,11 +193,14 @@ val screenModule = module {
195193
get(),
196194
get(),
197195
get(),
196+
get(),
197+
get()
198198
)
199199
}
200-
viewModel { (courseId: String) ->
200+
viewModel { (courseId: String, courseTitle: String) ->
201201
CourseOutlineViewModel(
202202
courseId,
203+
courseTitle,
203204
get(),
204205
get(),
205206
get(),
@@ -236,9 +237,10 @@ val screenModule = module {
236237
get(),
237238
)
238239
}
239-
viewModel { (courseId: String) ->
240+
viewModel { (courseId: String, courseTitle: String) ->
240241
CourseVideoViewModel(
241242
courseId,
243+
courseTitle,
242244
get(),
243245
get(),
244246
get(),
@@ -277,11 +279,8 @@ val screenModule = module {
277279
get(),
278280
)
279281
}
280-
viewModel { (courseId: String, courseName: String, isSelfPaced: Boolean, enrollmentMode: String) ->
282+
viewModel { (enrollmentMode: String) ->
281283
CourseDatesViewModel(
282-
courseId,
283-
courseName,
284-
isSelfPaced,
285284
enrollmentMode,
286285
get(),
287286
get(),
@@ -290,7 +289,6 @@ val screenModule = module {
290289
get(),
291290
get(),
292291
get(),
293-
get(),
294292
)
295293
}
296294
viewModel { (courseId: String, handoutsType: String) ->
@@ -307,13 +305,13 @@ val screenModule = module {
307305

308306
single { DiscussionRepository(get(), get(), get()) }
309307
factory { DiscussionInteractor(get()) }
310-
viewModel { (courseId: String) ->
308+
viewModel {
311309
DiscussionTopicsViewModel(
312310
get(),
313311
get(),
314312
get(),
315313
get(),
316-
courseId
314+
get()
317315
)
318316
}
319317
viewModel { (courseId: String, topicId: String, threadType: String) ->
@@ -377,4 +375,5 @@ val screenModule = module {
377375
viewModel { HtmlUnitViewModel(get(), get(), get(), get()) }
378376

379377
viewModel { ProgramViewModel(get(), get(), get(), get(), get(), get(), get()) }
378+
380379
}

build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ buildscript {
1313
}
1414

1515
plugins {
16-
id 'com.android.application' version '8.3.0' apply false
17-
id 'com.android.library' version '8.3.0' apply false
16+
id 'com.android.application' version '8.4.0' apply false
17+
id 'com.android.library' version '8.4.0' apply false
1818
id 'org.jetbrains.kotlin.android' version "$kotlin_version" apply false
1919
id 'com.google.gms.google-services' version '4.3.15' apply false
2020
id "com.google.firebase.crashlytics" version "2.9.6" apply false

catalog-info.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ metadata:
1010
- url: "https://github.com/openedx/openedx-app-android/tree/main/Documentation"
1111
title: "Documentation"
1212
icon: "PhoneAndroid"
13+
annotations:
14+
openedx.org/release: "main"
1315
spec:
1416
owner: group:openedx-mobile-maintainers
1517
type: 'mobile'

core/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ dependencies {
139139
// Koin DI
140140
api "io.insert-koin:koin-core:$koin_version"
141141
api "io.insert-koin:koin-android:$koin_version"
142+
api "io.insert-koin:koin-androidx-compose:$koin_version"
142143

143144
api "io.coil-kt:coil-compose:$coil_version"
144145
api "io.coil-kt:coil-gif:$coil_version"
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
@file:Suppress("DEPRECATION")
2+
3+
package org.openedx.core
4+
5+
import android.content.Context
6+
import android.graphics.Bitmap
7+
import android.graphics.drawable.Drawable
8+
import android.renderscript.Allocation
9+
import android.renderscript.RenderScript
10+
import android.renderscript.ScriptIntrinsicBlur
11+
import androidx.annotation.DrawableRes
12+
import coil.ImageLoader
13+
import coil.request.ImageRequest
14+
15+
class ImageProcessor(private val context: Context) {
16+
fun loadImage(
17+
@DrawableRes
18+
defaultImage: Int,
19+
imageUrl: String,
20+
onComplete: (result: Drawable) -> Unit
21+
) {
22+
val loader = ImageLoader(context)
23+
val request = ImageRequest.Builder(context)
24+
.data(imageUrl)
25+
.target { result ->
26+
onComplete(result)
27+
}
28+
.error(defaultImage)
29+
.placeholder(defaultImage)
30+
.allowHardware(false)
31+
.build()
32+
loader.enqueue(request)
33+
}
34+
35+
fun applyBlur(
36+
bitmap: Bitmap,
37+
blurRadio: Float
38+
): Bitmap {
39+
val renderScript = RenderScript.create(context)
40+
val bitmapAlloc = Allocation.createFromBitmap(renderScript, bitmap)
41+
ScriptIntrinsicBlur.create(renderScript, bitmapAlloc.element).apply {
42+
setRadius(blurRadio)
43+
setInput(bitmapAlloc)
44+
repeat(3) {
45+
forEach(bitmapAlloc)
46+
}
47+
}
48+
val newBitmap: Bitmap = Bitmap.createBitmap(
49+
bitmap.width,
50+
bitmap.height,
51+
Bitmap.Config.ARGB_8888
52+
)
53+
bitmapAlloc.copyTo(newBitmap)
54+
renderScript.destroy()
55+
return newBitmap
56+
}
57+
}

0 commit comments

Comments
 (0)