Initial Matomo integration. #101
12
.drone.yml
12
.drone.yml
@ -8,7 +8,7 @@ steps:
|
||||
commands:
|
||||
- echo "---------------------------------------------------------"
|
||||
- echo "Configure gradle..."
|
||||
- mkdir -p ~/.gradle && echo "org.gradle.daemon=false\nignoreGitVersion=true\nappLoginUrl=\"URL\"\nappLoginUsername=\"LOGIN\"\nappLoginPassword=\"PASS\"\npushCache=false\nsystemProp.org.gradle.internal.http.connectionTimeout=180000\nsystemProp.org.gradle.internal.http.socketTimeout=180000" >> ~/.gradle/gradle.properties
|
||||
- mkdir -p ~/.gradle && echo "org.gradle.daemon=false\nignoreGitVersion=true\npushCache=false\nmatomoUrl=\"$MATOMO_URL\"\nmatomoSite=\"$MATOMO_SITE\"\nsystemProp.org.gradle.internal.http.connectionTimeout=180000\nsystemProp.org.gradle.internal.http.socketTimeout=180000" >> ~/.gradle/gradle.properties
|
||||
- echo "---------------------------------------------------------"
|
||||
- echo "Analysing..."
|
||||
- ./gradlew sonarqube -Dsonar.projectKey=RFS2 -Dsonar.host.url=$SONAR_HOST_URL -Dsonar.login=$SONAR_LOGIN
|
||||
@ -24,6 +24,10 @@ steps:
|
||||
from_secret: sonarScannerHostUrl
|
||||
SONAR_LOGIN:
|
||||
from_secret: sonarScannerLogin
|
||||
MATOMO_URL:
|
||||
from_secret: matomoUrl
|
||||
MATOMO_SITE:
|
||||
from_secret: matomoSite
|
||||
trigger:
|
||||
event:
|
||||
- push
|
||||
@ -90,7 +94,7 @@ steps:
|
||||
commands:
|
||||
- echo "---------------------------------------------------------"
|
||||
- echo "Configure gradle..."
|
||||
- mkdir -p ~/.gradle && echo "org.gradle.daemon=false\nignoreGitVersion=true\nappLoginUrl=\"URL\"\nappLoginUsername=\"LOGIN\"\nappLoginPassword=\"PASS\"\npushCache=false\nsystemProp.org.gradle.internal.http.connectionTimeout=180000\nsystemProp.org.gradle.internal.http.socketTimeout=180000" >> ~/.gradle/gradle.properties
|
||||
- mkdir -p ~/.gradle && echo "org.gradle.daemon=false\nignoreGitVersion=true\nmatomoUrl=\"$MATOMO_URL\"\nmatomoSite=\"$MATOMO_SITE\"\npushCache=false\nsystemProp.org.gradle.internal.http.connectionTimeout=180000\nsystemProp.org.gradle.internal.http.socketTimeout=180000" >> ~/.gradle/gradle.properties
|
||||
- echo "---------------------------------------------------------"
|
||||
- echo "Generate APK"
|
||||
- ./gradlew :androidApp:assembleGithubConfigRelease -P pushCache=false
|
||||
@ -111,6 +115,10 @@ steps:
|
||||
from_secret: keyPass
|
||||
YOUR_KEY_ALIAS:
|
||||
from_secret: keyAlias
|
||||
MATOMO_URL:
|
||||
from_secret: matomoUrl
|
||||
MATOMO_SITE:
|
||||
from_secret: matomoSite
|
||||
|
||||
- name: gitea_release
|
||||
image: plugins/gitea-release
|
||||
|
9
.github/CONTRIBUTING.md
vendored
9
.github/CONTRIBUTING.md
vendored
@ -55,19 +55,18 @@ You'll have to:
|
||||
|
||||
- Define some parameters either in `~/.gradle/gradle.properties` or as gradle parameters (see the examples)
|
||||
|
||||
- appLoginUrl, appLoginUsername and appLoginPassword: url, username and password of a selfoss instance. **These are only used for tests. They can be empty if you don't test API calls.**
|
||||
- matomoUrl and matomoSite: url and siteId for a matomo instance
|
||||
|
||||
### Examples:
|
||||
#### Inside ~/.gradle/gradle.properties
|
||||
|
||||
```
|
||||
appLoginUrl="URL" # It can be empty.
|
||||
appLoginUsername="LOGIN" # It can be empty.
|
||||
appLoginPassword="PASS" # It can be empty.
|
||||
matomoUrl="URL" # It can be empty.
|
||||
matomoSite="1" # It can be empty, but needs to be an integer
|
||||
```
|
||||
|
||||
#### As gradle parameters
|
||||
|
||||
```
|
||||
./gradlew .... -P appLoginUrl="URL" -P appLoginUsername="LOGIN" -P appLoginPassword="PASS"
|
||||
./gradlew .... -P matomoUrl="URL" -P matomoSite="1"
|
||||
```
|
||||
|
@ -83,6 +83,9 @@ android {
|
||||
|
||||
// tests
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
buildConfigField("String", "MATOMO_URL", properties["matomoUrl"] as String)
|
||||
buildConfigField("String", "MATOMO_SITE", properties["matomoSite"] as String)
|
||||
}
|
||||
packagingOptions {
|
||||
resources {
|
||||
@ -96,9 +99,6 @@ android {
|
||||
proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
|
||||
}
|
||||
getByName("debug") {
|
||||
buildConfigField("String", "LOGIN_URL", properties["appLoginUrl"] as String)
|
||||
buildConfigField("String", "LOGIN_PASSWORD", properties["appLoginPassword"] as String)
|
||||
buildConfigField("String", "LOGIN_USERNAME", properties["appLoginUsername"] as String)
|
||||
}
|
||||
}
|
||||
flavorDimensions.add("build")
|
||||
@ -189,6 +189,9 @@ dependencies {
|
||||
testImplementation("io.mockk:mockk:1.12.0")
|
||||
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0")
|
||||
|
||||
// Matomo
|
||||
implementation("com.github.matomo-org:matomo-sdk-android:4.1.4")
|
||||
}
|
||||
|
||||
tasks.withType<Test> {
|
||||
|
@ -35,7 +35,10 @@ import bou.amine.apps.readerforselfossv2.android.utils.bottombar.removeBadge
|
||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
||||
import bou.amine.apps.readerforselfossv2.repository.Repository
|
||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||
import bou.amine.apps.readerforselfossv2.utils.*
|
||||
import bou.amine.apps.readerforselfossv2.utils.ItemType
|
||||
import bou.amine.apps.readerforselfossv2.utils.getHtmlDecoded
|
||||
import bou.amine.apps.readerforselfossv2.utils.getIcon
|
||||
import bou.amine.apps.readerforselfossv2.utils.longHash
|
||||
import com.ashokvarma.bottomnavigation.BottomNavigationBar
|
||||
import com.ashokvarma.bottomnavigation.BottomNavigationItem
|
||||
import com.ashokvarma.bottomnavigation.TextBadgeItem
|
||||
@ -59,6 +62,9 @@ import kotlinx.coroutines.launch
|
||||
import org.kodein.di.DIAware
|
||||
import org.kodein.di.android.closestDI
|
||||
import org.kodein.di.instance
|
||||
import org.matomo.sdk.Tracker
|
||||
import org.matomo.sdk.extra.DimensionQueue
|
||||
import org.matomo.sdk.extra.TrackHelper
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
|
||||
@ -95,12 +101,16 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
override val di by closestDI()
|
||||
private val repository : Repository by instance()
|
||||
private val appSettingsService : AppSettingsService by instance()
|
||||
private val tracker : Tracker by instance()
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityHomeBinding.inflate(layoutInflater)
|
||||
val view = binding.root
|
||||
|
||||
TrackHelper.track().screen("/home").with(tracker)
|
||||
|
||||
fromTabShortcut = intent.getIntExtra("shortcutTab", -1) != -1
|
||||
repository.offlineOverride = intent.getBooleanExtra("startOffline", false)
|
||||
|
||||
|
@ -25,6 +25,12 @@ import kotlinx.coroutines.launch
|
||||
import org.kodein.di.DIAware
|
||||
import org.kodein.di.android.closestDI
|
||||
import org.kodein.di.instance
|
||||
import org.matomo.sdk.Tracker
|
||||
import org.matomo.sdk.extra.DimensionQueue
|
||||
import org.matomo.sdk.extra.DownloadTracker
|
||||
import org.matomo.sdk.extra.TrackHelper
|
||||
import java.security.MessageDigest
|
||||
|
||||
|
||||
class LoginActivity : AppCompatActivity(), DIAware {
|
||||
|
||||
@ -36,10 +42,16 @@ class LoginActivity : AppCompatActivity(), DIAware {
|
||||
override val di by closestDI()
|
||||
private val repository : Repository by instance()
|
||||
private val appSettingsService : AppSettingsService by instance()
|
||||
private val tracker : Tracker by instance()
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
TrackHelper.track().download().identifier(DownloadTracker.Extra.ApkChecksum(applicationContext))
|
||||
.with(tracker)
|
||||
TrackHelper.track().screen("/login").with(tracker)
|
||||
|
||||
handleTheme()
|
||||
|
||||
binding = ActivityLoginBinding.inflate(layoutInflater)
|
||||
@ -102,6 +114,15 @@ class LoginActivity : AppCompatActivity(), DIAware {
|
||||
private fun goToMain() {
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
repository.updateApiVersion()
|
||||
|
||||
val messageDigest: MessageDigest = MessageDigest.getInstance("SHA-256")
|
||||
messageDigest.update(appSettingsService.getBaseUrl().toByteArray())
|
||||
tracker.userId = String(messageDigest.digest())
|
||||
|
||||
val mDimensionQueue = DimensionQueue(tracker)
|
||||
mDimensionQueue.add(1, appSettingsService.getApiVersion().toString())
|
||||
|
||||
tracker.isOptOut = !appSettingsService.isAnalyticsEnabled()
|
||||
}
|
||||
val intent = Intent(this, HomeActivity::class.java)
|
||||
startActivity(intent)
|
||||
|
@ -3,21 +3,16 @@ package bou.amine.apps.readerforselfossv2.android
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.widget.ImageView
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.appcompat.app.AppCompatDelegate.*
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.ProcessLifecycleOwner
|
||||
import androidx.multidex.MultiDexApplication
|
||||
import androidx.preference.PreferenceManager
|
||||
import bou.amine.apps.readerforselfossv2.DI.networkModule
|
||||
import bou.amine.apps.readerforselfossv2.android.utils.network.isNetworkAccessible
|
||||
import bou.amine.apps.readerforselfossv2.android.viewmodel.AppViewModel
|
||||
import bou.amine.apps.readerforselfossv2.dao.DriverFactory
|
||||
import bou.amine.apps.readerforselfossv2.dao.ReaderForSelfossDB
|
||||
@ -35,6 +30,9 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import org.kodein.di.*
|
||||
import org.matomo.sdk.Matomo
|
||||
import org.matomo.sdk.Tracker
|
||||
import org.matomo.sdk.TrackerBuilder
|
||||
|
||||
class MyApp : MultiDexApplication(), DIAware {
|
||||
|
||||
@ -45,12 +43,15 @@ class MyApp : MultiDexApplication(), DIAware {
|
||||
bind<Repository>() with singleton { Repository(instance(), instance(), isConnectionAvailable, instance()) }
|
||||
bind<ConnectivityStatus>() with singleton { ConnectivityStatus(applicationContext) }
|
||||
bind<AppViewModel>() with singleton { AppViewModel(repository = instance()) }
|
||||
bind<Tracker>() with singleton { TrackerBuilder.createDefault(BuildConfig.MATOMO_URL, BuildConfig.MATOMO_SITE.toInt()).build(
|
||||
Matomo.getInstance(applicationContext)) }
|
||||
}
|
||||
|
||||
private val repository: Repository by instance()
|
||||
private val viewModel: AppViewModel by instance()
|
||||
private val connectivityStatus: ConnectivityStatus by instance()
|
||||
private val driverFactory: DriverFactory by instance()
|
||||
private val tracker: Tracker by instance()
|
||||
|
||||
// TODO: handle with the "previous" way
|
||||
private val isConnectionAvailable: MutableStateFlow<Boolean> = MutableStateFlow(true)
|
||||
|
@ -17,16 +17,26 @@ import androidx.preference.PreferenceFragmentCompat
|
||||
import bou.amine.apps.readerforselfossv2.android.R
|
||||
import bou.amine.apps.readerforselfossv2.android.databinding.ActivitySettingsBinding
|
||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||
import org.kodein.di.DIAware
|
||||
import org.kodein.di.android.closestDI
|
||||
import org.kodein.di.instance
|
||||
import org.matomo.sdk.Tracker
|
||||
import org.matomo.sdk.extra.TrackHelper
|
||||
|
||||
private const val TITLE_TAG = "settingsActivityTitle"
|
||||
|
||||
class SettingsActivity : AppCompatActivity(),
|
||||
PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
|
||||
PreferenceFragmentCompat.OnPreferenceStartFragmentCallback, DIAware {
|
||||
override val di by closestDI()
|
||||
|
||||
private val tracker : Tracker by instance()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val binding = ActivitySettingsBinding.inflate(layoutInflater)
|
||||
|
||||
TrackHelper.track().screen("/settings").with(tracker)
|
||||
|
||||
setContentView(binding.root)
|
||||
if (savedInstanceState == null) {
|
||||
supportFragmentManager
|
||||
|
@ -133,4 +133,5 @@
|
||||
<string name="mode_system">Follow the system setting</string>
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
</resources>
|
||||
|
@ -133,4 +133,5 @@
|
||||
<string name="mode_system">Follow the system setting</string>
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
</resources>
|
||||
|
@ -133,4 +133,5 @@
|
||||
<string name="mode_system">Follow the system setting</string>
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
</resources>
|
||||
|
@ -133,4 +133,5 @@
|
||||
<string name="mode_system">Follow the system setting</string>
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
</resources>
|
||||
|
@ -133,4 +133,5 @@
|
||||
<string name="mode_system">Utiliser les paramètres système</string>
|
||||
<string name="mode_light">Thème clair</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
</resources>
|
||||
|
@ -133,4 +133,5 @@
|
||||
<string name="mode_system">Follow the system setting</string>
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
</resources>
|
||||
|
@ -133,4 +133,5 @@
|
||||
<string name="mode_system">Follow the system setting</string>
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
</resources>
|
||||
|
@ -133,4 +133,5 @@
|
||||
<string name="mode_system">Follow the system setting</string>
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
</resources>
|
||||
|
@ -133,4 +133,5 @@
|
||||
<string name="mode_system">Follow the system setting</string>
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
</resources>
|
||||
|
4
androidApp/src/main/res/values-night/strings.xml
Normal file
4
androidApp/src/main/res/values-night/strings.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
</resources>
|
@ -133,4 +133,5 @@
|
||||
<string name="mode_system">Follow the system setting</string>
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
</resources>
|
||||
|
@ -133,4 +133,5 @@
|
||||
<string name="mode_system">Follow the system setting</string>
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
</resources>
|
||||
|
@ -133,4 +133,5 @@
|
||||
<string name="mode_system">Follow the system setting</string>
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
</resources>
|
||||
|
@ -133,4 +133,5 @@
|
||||
<string name="mode_system">Follow the system setting</string>
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
</resources>
|
||||
|
@ -133,4 +133,5 @@
|
||||
<string name="mode_system">Follow the system setting</string>
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
</resources>
|
||||
|
@ -133,4 +133,5 @@
|
||||
<string name="mode_system">遵循系统设置</string>
|
||||
<string name="mode_light">浅色模式</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
</resources>
|
||||
|
@ -133,4 +133,5 @@
|
||||
<string name="mode_system">Follow the system setting</string>
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
</resources>
|
||||
|
@ -136,4 +136,5 @@
|
||||
<string name="mode_dark">Dark mode</string>
|
||||
<string name="mode_system">Follow the system setting</string>
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
</resources>
|
||||
|
@ -1,5 +1,12 @@
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<SwitchPreference
|
||||
android:defaultValue="true"
|
||||
app:iconSpaceReserved="false"
|
||||
android:key="enable_analytics"
|
||||
android:title="@string/pref_switch_enable_analytics" />
|
||||
|
||||
<EditTextPreference
|
||||
android:inputType="number"
|
||||
android:key="api_timeout"
|
||||
|
@ -36,6 +36,7 @@ class AppSettingsService {
|
||||
private var _staticBar: Boolean? = null
|
||||
private var _font: String = ""
|
||||
private var _theme: Int? = null
|
||||
private var _enableAnalytics: Boolean? = null
|
||||
|
||||
|
||||
init {
|
||||
@ -308,6 +309,17 @@ class AppSettingsService {
|
||||
return _staticBar == true
|
||||
}
|
||||
|
||||
private fun refreshAnalyticsEnabled() {
|
||||
_enableAnalytics = settings.getBoolean(ENABLE_ANALYTICS, true)
|
||||
}
|
||||
|
||||
fun isAnalyticsEnabled(): Boolean {
|
||||
if (_enableAnalytics != null) {
|
||||
refreshAnalyticsEnabled()
|
||||
}
|
||||
return _enableAnalytics == true
|
||||
}
|
||||
|
||||
private fun refreshFont() {
|
||||
_font = settings.getString(READER_FONT, "")
|
||||
}
|
||||
@ -359,6 +371,7 @@ class AppSettingsService {
|
||||
refreshFont()
|
||||
refreshStaticBarEnabled()
|
||||
refreshCurrentTheme()
|
||||
refreshAnalyticsEnabled()
|
||||
}
|
||||
|
||||
fun refreshLoginInformation(
|
||||
@ -459,5 +472,7 @@ class AppSettingsService {
|
||||
const val ITEMS_CACHING = "items_caching"
|
||||
|
||||
const val CURRENT_THEME = "currentMode"
|
||||
|
||||
const val ENABLE_ANALYTICS = "enable_analytics"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user