Skip to content

Commit

Permalink
Change methodology of fetching activities from year based queries to …
Browse files Browse the repository at this point in the history
…querying up to first 10 pages (#28)

* This commit addresses a possible concern that Strava's backend is failing when `before` and `after` properties are specified by migrating the code to instead query up to the first 10 pages of activities.
  • Loading branch information
Tyler-Lopez authored Feb 18, 2023
1 parent 73709b2 commit e3732d6
Show file tree
Hide file tree
Showing 48 changed files with 302 additions and 712 deletions.
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ android {
applicationId "com.activityartapp"
minSdk 26
targetSdk 33
versionCode 11
versionName "1.3.1"
versionCode 12
versionName "1.3.2"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
Expand Down
20 changes: 0 additions & 20 deletions app/src/main/java/com/activityartapp/data/Converters.kt

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@ package com.activityartapp.data.cache

import com.activityartapp.domain.models.Activity

/**
* Global Singleton cache data-layer which is populated during the first data load and
* then never again.
*/
class ActivitiesCache {
val cachedActivitiesByYear: MutableMap<Int, List<Activity>> = mutableMapOf()
var cachedActivities: List<Activity>? = null
}
14 changes: 14 additions & 0 deletions app/src/main/java/com/activityartapp/data/dao/ActivityDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,20 @@ interface ActivityDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAllActivities(vararg activityEntity: ActivityEntity)


/**
* Retrieves all activities which match the year provided.
* Functions by pattern recognition of the iso8601 String.
*/
@Query(
"SELECT * " +
"FROM activityEntity " +
"WHERE athleteId = :athleteId " +
"AND summaryPolyline IS NOT NULL"
)
suspend fun getActivities(athleteId: Long): List<ActivityEntity>


/**
* Retrieves all activities which match the year provided.
* Functions by pattern recognition of the iso8601 String.
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@ import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.activityartapp.data.entities.OAuth2Entity
import com.activityartapp.data.entities.AthleteEntity

@Dao
interface OAuth2Dao {
interface AthleteDao {

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertOauth2(oAuth2Entity: OAuth2Entity)
suspend fun insertAthlete(AthleteEntity: AthleteEntity)

// https://stackoverflow.com/questions/44244508/room-persistance-library-delete-all
@Query("DELETE FROM oAuth2Entity")
suspend fun clearOauth2()
@Query("DELETE FROM athleteEntity")
suspend fun clearAthlete()

@Query("SELECT * FROM oAuth2Entity")
suspend fun getCurrAuth(): OAuth2Entity?
@Query("SELECT * FROM athleteEntity")
suspend fun getCurrAthlete(): AthleteEntity?
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,21 @@ package com.activityartapp.data.database

import androidx.room.Database
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import com.activityartapp.data.Converters
import com.activityartapp.data.dao.ActivityDao
import com.activityartapp.data.dao.AthleteCacheDictionaryDao
import com.activityartapp.data.dao.OAuth2Dao
import com.activityartapp.data.dao.AthleteDao
import com.activityartapp.data.entities.ActivityEntity
import com.activityartapp.data.entities.AthleteCacheDictionaryEntity
import com.activityartapp.data.entities.OAuth2Entity
import com.activityartapp.data.entities.AthleteEntity

/**
* https://svvashishtha.medium.com/using-room-with-hilt-cb57a1bc32f
* https://developer.android.com/training/data-storage/room
*/

@Database(
entities = [ActivityEntity::class, AthleteCacheDictionaryEntity::class, OAuth2Entity::class],
version = 3
entities = [ActivityEntity::class, AthleteEntity::class],
version = 5
)
@TypeConverters(Converters::class)
abstract class AthleteDatabase : RoomDatabase() {
abstract val activityDao: ActivityDao
abstract val athleteCacheDictionaryDao: AthleteCacheDictionaryDao
abstract val oAuth2Dao: OAuth2Dao
abstract val athleteDao: AthleteDao
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package com.activityartapp.data.entities

import androidx.room.Entity
import androidx.room.PrimaryKey
import com.activityartapp.domain.models.Athlete
import com.activityartapp.domain.models.OAuth2

@Entity
data class OAuth2Entity(
data class AthleteEntity(
@PrimaryKey
override val athleteId: Long,
override val lastCachedUnixMs: Long?,
override val expiresAtUnixSeconds: Int,
override val accessToken: String,
override val refreshToken: String
) : OAuth2
) : Athlete
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ interface AthleteApi {
@GET("api/v3/athlete/activities?")
suspend fun getActivities(
@Header("Authorization") authHeader: String,
@Query("before") before: Int,
@Query("after") after: Int,
@Query("page") page: Int,
@Query("per_page") perPage: Int
): Activities
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ data class ActivityResponse(
override val iso8601LocalDate: String,
@SerializedName("suffer_score")
override val sufferScore: Int?,
val athlete: AthleteWithResourceState,
val athlete: AthleteResponse,
val map: Map?
) : Activity {
override val athleteId: Long
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package com.activityartapp.data.remote.responses

import com.activityartapp.domain.models.Athlete
import com.google.gson.annotations.SerializedName

data class AthleteResponse(
@SerializedName("id")
override val id: Long,
) : Athlete
val id: Long
)

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,4 @@ data class Bearer(
val athlete: AthleteResponse,
val expires_in: Int,
val token_type: String
) : OAuth2 {
override val athleteId: Long
get() = athlete.id
}
) : OAuth2
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.activityartapp.data.remote.responses

import com.activityartapp.domain.models.OAuth2WithoutAthlete
import com.activityartapp.domain.models.OAuth2
import com.google.gson.annotations.SerializedName

data class BearerWithoutAthlete(
Expand All @@ -12,4 +12,4 @@ data class BearerWithoutAthlete(
override val refreshToken: String,
val expires_in: Int,
val token_type: String
) : OAuth2WithoutAthlete
) : OAuth2

This file was deleted.

65 changes: 5 additions & 60 deletions app/src/main/java/com/activityartapp/di/AppModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,13 @@ import com.activityartapp.data.remote.AthleteApi
import com.activityartapp.data.repository.AthleteUsageRepositoryImpl
import com.activityartapp.data.repository.FileRepositoryImpl
import com.activityartapp.data.repository.VersionRepositoryImpl
import com.activityartapp.domain.models.ResolutionListFactory
import com.activityartapp.domain.repository.AthleteUsageRepository
import com.activityartapp.domain.repository.FileRepository
import com.activityartapp.domain.repository.VersionRepository
import com.activityartapp.domain.models.ResolutionListFactory
import com.activityartapp.domain.useCase.activities.*
import com.activityartapp.domain.useCase.athleteCacheDictionary.GetAthleteCacheDictionaryFromDisk
import com.activityartapp.domain.useCase.athleteCacheDictionary.InsertAthleteCacheDictionaryIntoDisk
import com.activityartapp.domain.useCase.athleteUsage.GetAthleteUsageFromRemote
import com.activityartapp.domain.useCase.athleteUsage.InsertAthleteUsageIntoRemote
import com.activityartapp.domain.useCase.authentication.ClearAccessTokenFromDisk
import com.activityartapp.domain.useCase.activities.GetActivitiesByPageFromRemote
import com.activityartapp.domain.useCase.activities.InsertActivitiesIntoMemory
import com.activityartapp.domain.useCase.authentication.ClearAthleteFromDisk
import com.activityartapp.presentation.editArtScreen.subscreens.resize.ResolutionListFactoryImpl
import com.activityartapp.util.*
import com.activityartapp.util.constants.TokenConstants
Expand Down Expand Up @@ -51,74 +48,22 @@ object AppModule {
@Provides
fun provideActivitiesCache() = ActivitiesCache()

@Provides
fun providesGetAthleteFromLocalUseCase(athleteDatabase: AthleteDatabase) =
GetAthleteCacheDictionaryFromDisk(athleteDatabase)

@Provides
fun providesGetActivitiesByPageFromRemoteUseCase(
api: AthleteApi
): GetActivitiesByPageFromRemote =
GetActivitiesByPageFromRemote(api)

@Provides
fun providesGetActivitiesByYearFromRemoteUseCase(
getActivitiesByPageFromRemote: GetActivitiesByPageFromRemote,
getAthleteUsageFromRemote: GetAthleteUsageFromRemote,
insertAthleteUsageIntoRemote: InsertAthleteUsageIntoRemote,
timeUtils: TimeUtils
) = GetActivitiesByYearFromRemote(
getActivitiesByPageFromRemote,
getAthleteUsageFromRemote,
insertAthleteUsageIntoRemote,
timeUtils
)

@Provides
fun providesGetActivitiesByYearFromLocalUseCase(
athleteDatabase: AthleteDatabase
) = GetActivitiesByYearFromDisk(athleteDatabase)

@Provides
fun providesGetActivitiesByYearMonthFromLocalUseCase(
athleteDatabase: AthleteDatabase
) = GetActivitiesByYearMonthFromDisk(athleteDatabase)

@Provides
fun providesGetActivitiesFromCacheUseCase(cache: ActivitiesCache) =
GetActivitiesByYearFromMemory(cache)

@Provides
fun providesInsertActivitiesFromCacheUseCase(cache: ActivitiesCache) =
InsertActivitiesIntoMemory(cache)

@Provides
fun providesGetActivitiesByYear(
getAthleteCacheDictionaryFromDisk: GetAthleteCacheDictionaryFromDisk,
getActivitiesByYearMonthFromDisk: GetActivitiesByYearMonthFromDisk,
getActivitiesByYearFromRemote: GetActivitiesByYearFromRemote,
insertActivitiesIntoDisk: InsertActivitiesIntoDisk,
insertActivitiesIntoMemory: InsertActivitiesIntoMemory,
timeUtils: TimeUtils
) = GetActivitiesByYearFromDiskOrRemote(
getAthleteCacheDictionaryFromDisk,
getActivitiesByYearMonthFromDisk,
getActivitiesByYearFromRemote,
insertActivitiesIntoDisk,
insertActivitiesIntoMemory,
timeUtils
)

@Provides
fun providesInsertAthleteFromRemoteUseCase(athleteDatabase: AthleteDatabase) =
InsertAthleteCacheDictionaryIntoDisk(athleteDatabase)

@Provides
fun clearAccessTokenUseCase(
athleteDatabase: AthleteDatabase,
cache: ActivitiesCache
) =
ClearAccessTokenFromDisk(athleteDatabase, cache)
ClearAthleteFromDisk(athleteDatabase, cache)

@Singleton
@Provides
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,4 @@ interface Activity {
val sufferScore: Int?
val summaryPolyline: String?
val sportType: SportType

}
15 changes: 7 additions & 8 deletions app/src/main/java/com/activityartapp/domain/models/Athlete.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package com.activityartapp.domain.models

/**
* [Athlete] is a registered athlete on Strava.
*
* @property id [id] is an athlete's ID, as provided by Strava.
*/
interface Athlete {
val id: Long
}
interface Athlete : OAuth2 {
val athleteId: Long
val lastCachedUnixMs: Long?
override val expiresAtUnixSeconds: Int
override val accessToken: String
override val refreshToken: String
}
Loading

0 comments on commit e3732d6

Please sign in to comment.