Skip to content

Commit 8c57627

Browse files
Merge pull request #230 from openedx/develop
Develop to main v1.4
2 parents c736918 + e6876be commit 8c57627

File tree

356 files changed

+18791
-4594
lines changed

Some content is hidden

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

356 files changed

+18791
-4594
lines changed

.github/workflows/unit_tests.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ jobs:
3636
uses: gradle/[email protected]
3737
with:
3838
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
39-
39+
- name: Generate mock files
40+
run: ./gradlew generateMockedRawFile
4041
- name: Run unit tests
4142
run: ./gradlew testProdReleaseUnitTest $CI_GRADLE_ARG_PROPERTIES
4243

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@
1414
.cxx
1515
local.properties
1616
/.idea/
17-
*.log
17+
*.log
18+
/config_settings.yaml

README.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,29 @@ Modern vision of the mobile application for the Open EdX platform from Raccoon G
55
[Documentation](Documentation/Documentation.md)
66

77
## Building
8+
89
1. Check out the source code:
910

10-
git clone https://github.com/raccoongang/educationx-app-ios.git
11+
git clone https://github.com/openedx/openedx-app-android.git
1112

1213
2. Open Android Studio and choose Open an Existing Android Studio Project.
1314

14-
3. Choose ``educationx-app-android``.
15+
3. Choose ``openedx-app-android``.
1516

16-
4. Configure the [config.yaml](config.yaml) with URLs and OAuth credentials for your Open edX instance.
17+
4. Configure the [config.yaml](default_config/dev/config.yaml) with URLs and OAuth credentials for your Open edX instance.
1718

1819
5. Select the build variant ``develop``, ``stage``, or ``prod``.
1920

2021
6. Click the **Run** button.
2122

2223
## API plugin
24+
2325
This project uses custom APIs to improve performance and reduce the number of requests to the server.
2426

2527
You can find the plugin with the API and installation guide [here](https://github.com/raccoongang/mobile-api-extensions).
2628

2729
## License
30+
2831
The code in this repository is licensed under the Apache-2.0 license unless otherwise noted.
2932

30-
Please see [LICENSE](https://github.com/raccoongang/educationx-app-android/blob/main/LICENSE) file for details.
33+
Please see [LICENSE](https://github.com/openedx/openedx-app-android/blob/main/LICENSE) file for details.

app/build.gradle

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,22 @@ plugins {
33
id 'org.jetbrains.kotlin.android'
44
id 'kotlin-parcelize'
55
id 'kotlin-kapt'
6-
id "com.google.firebase.crashlytics"
6+
id 'com.google.firebase.crashlytics'
77
}
88

9+
def config = configHelper.fetchConfig()
10+
def appId = config.getOrDefault("APPLICATION_ID", "org.openedx.app")
11+
def platformName = config.getOrDefault("PLATFORM_NAME", "OpenEdx").toLowerCase()
12+
913
android {
1014
compileSdk 34
1115

1216
defaultConfig {
13-
applicationId "org.openedx.app"
17+
applicationId appId
1418
minSdk 24
1519
targetSdk 34
1620
versionCode 1
17-
versionName "1.0"
21+
versionName "1.0.0"
1822

1923
resourceConfigurations += ["en", "uk"]
2024

@@ -36,10 +40,26 @@ android {
3640
}
3741
}
3842

43+
sourceSets {
44+
prod {
45+
res.srcDirs = ["src/$platformName/res"]
46+
}
47+
develop {
48+
res.srcDirs = ["src/$platformName/res"]
49+
}
50+
stage {
51+
res.srcDirs = ["src/$platformName/res"]
52+
}
53+
}
54+
3955
buildTypes {
4056
release {
4157
minifyEnabled true
4258
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
59+
60+
firebaseCrashlytics {
61+
mappingFileUploadEnabled false
62+
}
4363
}
4464
}
4565
compileOptions {
@@ -80,6 +100,7 @@ dependencies {
80100
implementation project(path: ':discovery')
81101
implementation project(path: ':profile')
82102
implementation project(path: ':discussion')
103+
implementation project(path: ':whatsnew')
83104

84105
kapt "androidx.room:room-compiler:$room_version"
85106

app/proguard-rules.pro

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
#-keep class com.google.gson.stream.** { *; }
7575

7676
# Application classes that will be serialized/deserialized over Gson
77-
-keep class com.google.gson.examples.android.model.** { <fields>; }
77+
-keep class org.openedx.*.data.model.** { <fields>; }
7878

7979
# Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
8080
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
@@ -93,3 +93,19 @@
9393
-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken
9494

9595
##---------------End: proguard configuration for Gson ----------
96+
97+
-keepclassmembers class * extends java.lang.Enum {
98+
<fields>;
99+
public static **[] values();
100+
public static ** valueOf(java.lang.String);
101+
}
102+
103+
-dontwarn org.bouncycastle.jsse.BCSSLParameters
104+
-dontwarn org.bouncycastle.jsse.BCSSLSocket
105+
-dontwarn org.bouncycastle.jsse.provider.BouncyCastleJsseProvider
106+
-dontwarn org.conscrypt.Conscrypt$Version
107+
-dontwarn org.conscrypt.Conscrypt
108+
-dontwarn org.conscrypt.ConscryptHostnameVerifier
109+
-dontwarn org.openjsse.javax.net.ssl.SSLParameters
110+
-dontwarn org.openjsse.javax.net.ssl.SSLSocket
111+
-dontwarn org.openjsse.net.ssl.OpenJSSE

app/src/main/AndroidManifest.xml

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
<uses-permission android:name="android.permission.INTERNET" />
66
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
7+
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
78

89
<queries>
910
<intent>
@@ -15,19 +16,20 @@
1516
android:name=".OpenEdXApp"
1617
android:allowBackup="false"
1718
android:dataExtractionRules="@xml/data_extraction_rules"
19+
android:enableOnBackInvokedCallback="true"
1820
android:fullBackupContent="@xml/backup_rules"
1921
android:icon="@mipmap/ic_launcher"
2022
android:label="@string/app_name"
2123
android:localeConfig="@xml/locales_config"
2224
android:roundIcon="@mipmap/ic_launcher_round"
25+
android:screenOrientation="sensor"
2326
android:supportsRtl="true"
2427
android:theme="@style/Theme.App.Starting"
2528
tools:targetApi="tiramisu">
2629
<activity
2730
android:name=".AppActivity"
2831
android:exported="true"
2932
android:fitsSystemWindows="true"
30-
android:screenOrientation="portrait"
3133
android:theme="@style/Theme.App.Starting"
3234
android:windowSoftInputMode="adjustPan">
3335
<intent-filter>
@@ -47,10 +49,20 @@
4749
android:resource="@xml/file_provider_paths" />
4850
</provider>
4951

50-
<provider android:authorities="${applicationId}.firebaseinitprovider"
52+
<provider
5153
android:name="com.google.firebase.provider.FirebaseInitProvider"
54+
android:authorities="${applicationId}.firebaseinitprovider"
5255
android:exported="false"
53-
tools:node="remove"/>
56+
tools:node="remove" />
57+
58+
<meta-data
59+
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
60+
android:value="androidx.media3.cast.DefaultCastOptionsProvider" />
61+
62+
<service
63+
android:name="androidx.work.impl.foreground.SystemForegroundService"
64+
android:foregroundServiceType="dataSync"
65+
tools:node="merge" />
5466
</application>
5567

56-
</manifest>
68+
</manifest>

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

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,45 @@ package org.openedx.app
33
import android.content.Context
44
import android.os.Bundle
55
import androidx.core.os.bundleOf
6-
import com.google.firebase.analytics.FirebaseAnalytics
6+
import org.openedx.app.analytics.Analytics
7+
import org.openedx.app.analytics.FirebaseAnalytics
78
import org.openedx.auth.presentation.AuthAnalytics
9+
import org.openedx.core.config.Config
810
import org.openedx.course.presentation.CourseAnalytics
9-
import org.openedx.dashboard.presentation.DashboardAnalytics
11+
import org.openedx.dashboard.presentation.dashboard.DashboardAnalytics
1012
import org.openedx.discovery.presentation.DiscoveryAnalytics
1113
import org.openedx.discussion.presentation.DiscussionAnalytics
1214
import org.openedx.profile.presentation.ProfileAnalytics
1315

14-
class AnalyticsManager(context: Context) : DashboardAnalytics, AuthAnalytics, AppAnalytics,
16+
class AnalyticsManager(
17+
context: Context,
18+
config: Config,
19+
) : DashboardAnalytics, AuthAnalytics, AppAnalytics,
1520
DiscoveryAnalytics, ProfileAnalytics, CourseAnalytics, DiscussionAnalytics {
1621

17-
private val analytics = FirebaseAnalytics.getInstance(context)
22+
private val services: ArrayList<Analytics> = arrayListOf()
23+
24+
init {
25+
// Initialise all the analytics libraries here
26+
if (config.getFirebaseConfig().projectId.isNotEmpty()) {
27+
addAnalyticsTracker(FirebaseAnalytics(context = context))
28+
}
29+
}
30+
31+
private fun addAnalyticsTracker(analytic: Analytics) {
32+
services.add(analytic)
33+
}
1834

1935
private fun logEvent(event: Event, params: Bundle = bundleOf()) {
20-
analytics.logEvent(event.eventName, params)
36+
services.forEach { analytics ->
37+
analytics.logEvent(event.eventName, params)
38+
}
2139
}
2240

2341
private fun setUserId(userId: Long) {
24-
analytics.setUserId(userId.toString())
42+
services.forEach { analytics ->
43+
analytics.logUserId(userId)
44+
}
2545
}
2646

2747
override fun dashboardCourseClickedEvent(courseId: String, courseName: String) {
@@ -143,10 +163,22 @@ class AnalyticsManager(context: Context) : DashboardAnalytics, AuthAnalytics, Ap
143163
logEvent(Event.PRIVACY_POLICY_CLICKED)
144164
}
145165

166+
override fun termsOfUseClickedEvent() {
167+
logEvent(Event.TERMS_OF_USE_CLICKED)
168+
}
169+
146170
override fun cookiePolicyClickedEvent() {
147171
logEvent(Event.COOKIE_POLICY_CLICKED)
148172
}
149173

174+
override fun dataSellClickedEvent() {
175+
logEvent(Event.DATE_SELL_CLICKED)
176+
}
177+
178+
override fun faqClickedEvent() {
179+
logEvent(Event.FAQ_CLICKED)
180+
}
181+
150182
override fun emailSupportClickedEvent() {
151183
logEvent(Event.EMAIL_SUPPORT_CLICKED)
152184
}
@@ -320,6 +352,15 @@ class AnalyticsManager(context: Context) : DashboardAnalytics, AuthAnalytics, Ap
320352
)
321353
}
322354

355+
override fun datesTabClickedEvent(courseId: String, courseName: String) {
356+
logEvent(
357+
Event.DATES_TAB_CLICKED, bundleOf(
358+
Key.COURSE_ID.keyName to courseId,
359+
Key.COURSE_NAME.keyName to courseName
360+
)
361+
)
362+
}
363+
323364
override fun handoutsTabClickedEvent(courseId: String, courseName: String) {
324365
logEvent(
325366
Event.HANDOUTS_TAB_CLICKED, bundleOf(
@@ -386,7 +427,10 @@ private enum class Event(val eventName: String) {
386427
PROFILE_DELETE_ACCOUNT_CLICKED("Profile_Delete_Account_Clicked"),
387428
PROFILE_VIDEO_SETTINGS_CLICKED("Profile_Video_settings_Clicked"),
388429
PRIVACY_POLICY_CLICKED("Privacy_Policy_Clicked"),
430+
TERMS_OF_USE_CLICKED("Terms_Of_Use_Clicked"),
389431
COOKIE_POLICY_CLICKED("Cookie_Policy_Clicked"),
432+
DATE_SELL_CLICKED("Data_Sell_Clicked"),
433+
FAQ_CLICKED("FAQ_Clicked"),
390434
EMAIL_SUPPORT_CLICKED("Email_Support_Clicked"),
391435
COURSE_ENROLL_CLICKED("Course_Enroll_Clicked"),
392436
COURSE_ENROLL_SUCCESS("Course_Enroll_Success"),
@@ -402,6 +446,7 @@ private enum class Event(val eventName: String) {
402446
COURSE_TAB_CLICKED("Course_Outline_Course_tab_Clicked"),
403447
VIDEO_TAB_CLICKED("Course_Outline_Videos_tab_Clicked"),
404448
DISCUSSION_TAB_CLICKED("Course_Outline_Discussion_tab_Clicked"),
449+
DATES_TAB_CLICKED("Course_Outline_Dates_tab_Clicked"),
405450
HANDOUTS_TAB_CLICKED("Course_Outline_Handouts_tab_Clicked"),
406451
DISCUSSION_ALL_POSTS_CLICKED("Discussion_All_Posts_Clicked"),
407452
DISCUSSION_FOLLOWING_CLICKED("Discussion_Following_Clicked"),

0 commit comments

Comments
 (0)