danger-dangermattic 1.2.2 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/CHANGELOG.md +6 -0
  4. data/Gemfile.lock +95 -57
  5. data/lib/dangermattic/gem_version.rb +1 -1
  6. data/lib/dangermattic/plugins/android_unit_test_checker.rb +7 -4
  7. data/lib/dangermattic/plugins/manifest_pr_checker.rb +13 -1
  8. data/lib/dangermattic/plugins/podfile_checker.rb +2 -0
  9. data/rakelib/console.rake +1 -1
  10. data/rakelib/git_helpers.rake +1 -1
  11. data/spec/android_unit_test_checker_spec.rb +93 -3
  12. data/spec/fixtures/android_unit_test_checker/MixDataPlusNormalClass.kt +14 -0
  13. data/spec/fixtures/android_unit_test_checker/src/main/java/com/dayoneapp/dayone/api/ApiResult.kt +69 -0
  14. data/spec/fixtures/android_unit_test_checker/src/main/java/com/dayoneapp/dayone/api/WebRecordApi.kt +49 -0
  15. data/spec/fixtures/android_unit_test_checker/src/main/java/com/dayoneapp/dayone/domain/drive/UiStates.kt +13 -0
  16. data/spec/fixtures/android_unit_test_checker/src/main/java/com/dayoneapp/dayone/main/settings/integrations/connect/AppIntegrationModule.kt +29 -0
  17. data/spec/fixtures/android_unit_test_checker/src/main/java/com/dayoneapp/dayone/main/streaks/StreaksViewModel.kt +377 -0
  18. data/spec/fixtures/android_unit_test_checker/src/main/java/com/dayoneapp/dayone/mediastorage/MediaStorageConfiguration.kt +31 -0
  19. data/spec/fixtures/android_unit_test_checker/src/main/java/com/dayoneapp/dayone/utils/AccountType.kt +15 -0
  20. data/spec/fixtures/android_unit_test_checker/src/main/java/com/dayoneapp/dayone/utils/usecase/SelectPhotoUseCase.kt +76 -0
  21. data/spec/pr_size_checker_spec.rb +14 -14
  22. data/spec/spec_helper.rb +8 -2
  23. data/spec/view_changes_checker_spec.rb +15 -15
  24. metadata +11 -2
@@ -0,0 +1,29 @@
1
+ package com.dayoneapp.dayone.main.settings.integrations.connect
2
+
3
+ import com.dayoneapp.dayone.main.settings.integrations.IntegrationAppId
4
+ import com.dayoneapp.dayone.main.settings.integrations.strava.StravaAppIntegrationHandler
5
+ import dagger.Module
6
+ import dagger.Provides
7
+ import dagger.hilt.InstallIn
8
+ import dagger.hilt.components.SingletonComponent
9
+ import javax.inject.Qualifier
10
+ import javax.inject.Singleton
11
+ import kotlin.jvm.JvmWildcard
12
+
13
+ @Qualifier
14
+ @Retention(AnnotationRetention.BINARY)
15
+ annotation class AppIntegrationHandlers
16
+
17
+ @Module
18
+ @InstallIn(SingletonComponent::class)
19
+ internal object AppIntegrationModule {
20
+ @Provides
21
+ @Singleton
22
+ @AppIntegrationHandlers
23
+ fun provideAppIntegrationHandlers(
24
+ stravaAppIntegrationHandler: StravaAppIntegrationHandler,
25
+ ): Map<IntegrationAppId, @JvmWildcard AppIntegrationHandler> =
26
+ mapOf(
27
+ IntegrationAppId.STRAVA to stravaAppIntegrationHandler,
28
+ )
29
+ }
@@ -0,0 +1,377 @@
1
+ package com.dayoneapp.dayone.main.streaks
2
+
3
+ import android.content.Context
4
+ import android.graphics.Bitmap
5
+ import androidx.annotation.ColorRes
6
+ import androidx.annotation.VisibleForTesting
7
+ import androidx.lifecycle.ViewModel
8
+ import androidx.lifecycle.viewModelScope
9
+ import com.dayoneapp.dayone.di.DatabaseThreadDispatcher
10
+ import com.dayoneapp.dayone.domain.JournalRepository
11
+ import com.dayoneapp.dayone.domain.SelectedJournalsProvider
12
+ import com.dayoneapp.dayone.domain.StreakRepository
13
+ import com.dayoneapp.dayone.domain.UserRepository
14
+ import com.dayoneapp.dayone.domain.analytics.AnalyticsTracker
15
+ import com.dayoneapp.dayone.domain.analytics.InitialContent
16
+ import com.dayoneapp.dayone.domain.entry.EntryRepository
17
+ import com.dayoneapp.dayone.main.editor.EditorLauncher
18
+ import com.dayoneapp.dayone.main.editor.MainActivityLauncher
19
+ import com.dayoneapp.dayone.main.navigation.ActivityEventHandler
20
+ import com.dayoneapp.dayone.main.navigation.Navigator
21
+ import com.dayoneapp.dayone.main.sharedjournals.events.OpenJournalOnTimeline
22
+ import com.dayoneapp.dayone.utils.DOStreakCalculator
23
+ import com.dayoneapp.dayone.utils.TimeProvider
24
+ import com.dayoneapp.dayone.utils.UtilsWrapper
25
+ import dagger.hilt.android.lifecycle.HiltViewModel
26
+ import kotlinx.coroutines.CoroutineDispatcher
27
+ import kotlinx.coroutines.flow.MutableStateFlow
28
+ import kotlinx.coroutines.flow.SharingStarted
29
+ import kotlinx.coroutines.flow.asStateFlow
30
+ import kotlinx.coroutines.flow.combine
31
+ import kotlinx.coroutines.flow.distinctUntilChanged
32
+ import kotlinx.coroutines.flow.map
33
+ import kotlinx.coroutines.flow.stateIn
34
+ import kotlinx.coroutines.launch
35
+ import java.io.File
36
+ import java.time.DayOfWeek
37
+ import java.time.LocalDate
38
+ import java.util.Calendar
39
+ import javax.inject.Inject
40
+
41
+ @HiltViewModel
42
+ class StreaksViewModel
43
+ @Inject
44
+ constructor(
45
+ @DatabaseThreadDispatcher private val databaseDispatcher: CoroutineDispatcher,
46
+ private val entryRepository: EntryRepository,
47
+ private val journalRepository: JournalRepository,
48
+ private val streakRepository: StreakRepository,
49
+ private val streaksCalculator: DOStreakCalculator,
50
+ private val timeProvider: TimeProvider,
51
+ private val userRepository: UserRepository,
52
+ private val navigator: Navigator,
53
+ private val selectedJournalsProvider: SelectedJournalsProvider,
54
+ private val utilsWrapper: UtilsWrapper,
55
+ private val analyticsTracker: AnalyticsTracker,
56
+ private val mainActivityLauncher: MainActivityLauncher,
57
+ private val editorLauncher: EditorLauncher,
58
+ private val activityEventHandler: ActivityEventHandler,
59
+ ) : ViewModel() {
60
+ val uiState =
61
+ combine(
62
+ entryRepository.liveEntryCount().distinctUntilChanged(),
63
+ entryRepository.liveEntryCountForDate().distinctUntilChanged(),
64
+ journalRepository
65
+ .getAllJournalsLive(false)
66
+ .map { journals ->
67
+ journals.map { journal -> journal.isHideStreaksEnabled }
68
+ }.distinctUntilChanged(),
69
+ ) { _, _, _ ->
70
+ val streakDays = streaksCalculator.calculateStreakWithSharedJournals()
71
+ val journals = getStreakJournals()
72
+ val streakWeekDays = getStreakWeekDays()
73
+
74
+ UiState.Streaks(
75
+ streakDays = streakDays,
76
+ streakWeekDays = streakWeekDays,
77
+ journals = journals,
78
+ )
79
+ }.stateIn(viewModelScope, SharingStarted.Lazily, UiState.Loading)
80
+
81
+ private val _journalOptionsState = MutableStateFlow<JournalOptionsState?>(null)
82
+ val journalOptionsState = _journalOptionsState.asStateFlow()
83
+
84
+ private val dayOfWeekList: DaysOfWeekList = DaysOfWeekList(timeProvider.getFirstDayOfWeek())
85
+
86
+ fun shareStreaks(
87
+ bitmap: Bitmap,
88
+ context: Context,
89
+ ) {
90
+ viewModelScope.launch(databaseDispatcher) {
91
+ analyticsTracker.trackButtonTapped("streakView_share")
92
+ val streaksFile: File = utilsWrapper.saveBitmapToFile(context, bitmap, "streaks_file")
93
+ utilsWrapper.shareImage(context, streaksFile.absolutePath)
94
+ }
95
+ }
96
+
97
+ fun close() {
98
+ viewModelScope.launch {
99
+ analyticsTracker.trackButtonTapped("streakView_close")
100
+ navigator.goBack()
101
+ }
102
+ }
103
+
104
+ fun showJournalOptions(
105
+ journalId: Int,
106
+ journalName: String,
107
+ ) {
108
+ viewModelScope.launch {
109
+ analyticsTracker.trackButtonTapped("streakView_journal")
110
+ _journalOptionsState.value = JournalOptionsState(journalId, journalName)
111
+ }
112
+ }
113
+
114
+ fun openJournal(journalId: Int) {
115
+ viewModelScope.launch {
116
+ _journalOptionsState.value = null
117
+
118
+ analyticsTracker.trackButtonTapped("streakView_journalMenu_openJournal")
119
+
120
+ activityEventHandler.sendEvent(
121
+ OpenJournalOnTimeline(
122
+ journalId = journalId,
123
+ selectedJournalsProvider = selectedJournalsProvider,
124
+ mainActivityLauncher = mainActivityLauncher,
125
+ ),
126
+ )
127
+ }
128
+ }
129
+
130
+ fun createEntry(journalId: Int) {
131
+ viewModelScope.launch {
132
+ _journalOptionsState.value = null
133
+
134
+ analyticsTracker.trackButtonTapped("streakView_journalMenu_createEntry")
135
+
136
+ val newEntry =
137
+ entryRepository.createNewEntry(
138
+ journalId = journalId,
139
+ )
140
+ val newEntryInformation =
141
+ EditorLauncher.NewEntryInformation(
142
+ AnalyticsTracker.NewEntrySource.STREAKS,
143
+ InitialContent.BLANK,
144
+ )
145
+ editorLauncher.editNewEntry(
146
+ entry = newEntry,
147
+ newEntryInformation = newEntryInformation,
148
+ navigateTo = navigator::navigateTo,
149
+ )
150
+ }
151
+ }
152
+
153
+ fun closeJournalOptions() {
154
+ _journalOptionsState.value = null
155
+ }
156
+
157
+ private suspend fun getStreakWeekDays(): List<StreakWeekDay> {
158
+ val week = mutableListOf<StreakWeekDay>()
159
+ // First day of the week can vary based on the user's locale. Generally, SUNDAY is the default in countries
160
+ // influenced by the US, MONDAY is standard in most of Europe and Asia, and SATURDAY can be common in some
161
+ // Middle Eastern countries due to the weekend structure.
162
+ val firstDayOfWeek = timeProvider.getFirstDayOfWeek()
163
+ if (firstDayOfWeek == Calendar.SATURDAY) {
164
+ week.add(getStreakWeekDay(DayOfWeek.SATURDAY))
165
+ }
166
+ if (firstDayOfWeek == Calendar.SUNDAY || firstDayOfWeek == Calendar.SATURDAY) {
167
+ week.add(getStreakWeekDay(DayOfWeek.SUNDAY))
168
+ }
169
+ week.add(getStreakWeekDay(DayOfWeek.MONDAY))
170
+ week.add(getStreakWeekDay(DayOfWeek.TUESDAY))
171
+ week.add(getStreakWeekDay(DayOfWeek.WEDNESDAY))
172
+ week.add(getStreakWeekDay(DayOfWeek.THURSDAY))
173
+ week.add(getStreakWeekDay(DayOfWeek.FRIDAY))
174
+ if (firstDayOfWeek != Calendar.SATURDAY) {
175
+ week.add(getStreakWeekDay(DayOfWeek.SATURDAY))
176
+ }
177
+ if (firstDayOfWeek != Calendar.SUNDAY && firstDayOfWeek != Calendar.SATURDAY) {
178
+ week.add(getStreakWeekDay(DayOfWeek.SUNDAY))
179
+ }
180
+
181
+ return week
182
+ }
183
+
184
+ @VisibleForTesting
185
+ suspend fun getStreakWeekDay(dayOfWeek: DayOfWeek): StreakWeekDay {
186
+ val currentDate = timeProvider.currentLocalDate()
187
+ val daysToDayOfWeek =
188
+ dayOfWeekList.daysToPreviousDay(
189
+ currentDay = currentDate.dayOfWeek,
190
+ previousDay = dayOfWeek,
191
+ )
192
+ // Go to the previous date based on [dateOfWeek] and current date.
193
+ val currentDateForDayOfWeek = currentDate.minusDays(daysToDayOfWeek.daysToPreviousDay.toLong())
194
+ // From that date, go back DAYS_MINUS_WEEK * 7 days to cover DAYS_MINUS_WEEK (18) instances of the [dayOfWeek].
195
+ // For example,if [dayOfWeek] is MONDAY and current date is 2024-10-8 (a TUESDAY), then [daysToDayOfWeek] is 1
196
+ // and [currentDateForDayOfWeek] is 2024-10-7 and since becomes 2024-6-7 which represents the 18th MONDAY from
197
+ // the current date.
198
+ val previousWeeks = if (daysToDayOfWeek.wasInPreviousWeek) DAYS_MINUS_WEEK - 1 else DAYS_MINUS_WEEK
199
+ val since = currentDateForDayOfWeek.minusDays(previousWeeks * 7)
200
+ // Generates a sequences of dates that represents the [dayOfWeek] for the previous 18 weeks. For the previous
201
+ // example, represent dates for each MONDAY from 2024-6-7 to 2024-10-7.
202
+ val dateRange: Sequence<LocalDate> =
203
+ generateSequence(since) { date ->
204
+ if (date < currentDateForDayOfWeek) date.plusDays(7) else null
205
+ }
206
+ // We query all the dates with entries since 2024-6-7 and check if the [dayOfWeek] for each week has an entry.
207
+ val userId = userRepository.getUser()?.id
208
+ val datesWithEntries = streakRepository.getDatesThatHaveEntriesSince(since, userId)
209
+ val days =
210
+ dateRange
211
+ .map { date ->
212
+ DayJournaled(datesWithEntries.contains(date))
213
+ }.toMutableList()
214
+ .also {
215
+ if (daysToDayOfWeek.wasInPreviousWeek) {
216
+ it.add(DayJournaled(null))
217
+ }
218
+ }
219
+
220
+ return StreakWeekDay(dayOfWeek = dayOfWeek, days = days)
221
+ }
222
+
223
+ @VisibleForTesting
224
+ suspend fun getStreakJournals(): List<StreakJournal> {
225
+ val currentDate = timeProvider.currentLocalDate()
226
+ val since = currentDate.minusDays(DAYS_MINUS_JOURNAL)
227
+ val dateRange: Sequence<LocalDate> =
228
+ generateSequence(since) { date ->
229
+ if (date < currentDate) date.plusDays(1) else null
230
+ }
231
+ return journalRepository
232
+ .getAllJournals(includeHidden = true)
233
+ .filter {
234
+ !it.isHideFromStreakEnabledNonNull() && !it.isPlaceholderForEncryptedJournalNonNull()
235
+ }.sortedBy { it.sortOrder ?: 0 }
236
+ .map { journal ->
237
+ val datesWithEntries =
238
+ if (journal.isShared == true) {
239
+ streakRepository.getDatesThatHaveEntriesSinceForSharedJournal(
240
+ journalId = journal.id,
241
+ since = since,
242
+ userId = userRepository.getUser()?.id ?: "",
243
+ )
244
+ } else {
245
+ streakRepository.getDatesThatHaveEntriesSinceForJournal(journalId = journal.id, since = since)
246
+ }
247
+ val days =
248
+ dateRange
249
+ .map { date ->
250
+ DayJournaled(datesWithEntries.contains(date))
251
+ }.toList()
252
+ val entriesToday =
253
+ if (journal.isShared == true) {
254
+ streakRepository.getNumEntriesForSharedJournalOnDate(
255
+ journalId = journal.id,
256
+ date = currentDate,
257
+ userId = userRepository.getUser()?.id ?: "",
258
+ )
259
+ } else {
260
+ streakRepository.getNumEntriesOnDate(journalId = journal.id, date = currentDate)
261
+ }
262
+
263
+ StreakJournal(
264
+ journalId = journal.id,
265
+ journalName = journal.name ?: "",
266
+ entriesToday = entriesToday,
267
+ color = journal.journalColor.backgroundColorRes,
268
+ days = days,
269
+ )
270
+ }
271
+ }
272
+
273
+ companion object {
274
+ private const val DAYS_MINUS_JOURNAL = 18L
275
+ private const val DAYS_MINUS_WEEK = 17L
276
+ }
277
+
278
+ sealed interface UiState {
279
+ data object Loading : UiState
280
+
281
+ data class Streaks(
282
+ val streakDays: Int,
283
+ val streakWeekDays: List<StreakWeekDay>,
284
+ val journals: List<StreakJournal>,
285
+ ) : UiState
286
+ }
287
+
288
+ class JournalOptionsState(
289
+ val journalId: Int,
290
+ val journalName: String,
291
+ )
292
+ }
293
+
294
+ data class StreakWeekDay(
295
+ val dayOfWeek: DayOfWeek,
296
+ val days: List<DayJournaled>,
297
+ )
298
+
299
+ @JvmInline
300
+ value class DayJournaled(
301
+ val isFilled: Boolean?,
302
+ )
303
+
304
+ data class StreakJournal(
305
+ val journalId: Int,
306
+ val journalName: String,
307
+ val entriesToday: Int,
308
+ @ColorRes
309
+ val color: Int,
310
+ val days: List<DayJournaled>,
311
+ )
312
+
313
+ private class DaysOfWeekList(
314
+ private val firstDayOfWeek: Int,
315
+ ) {
316
+ private val days =
317
+ buildList {
318
+ if (firstDayOfWeek == Calendar.SATURDAY) {
319
+ add(DayOfWeek.SATURDAY)
320
+ }
321
+ if (firstDayOfWeek == Calendar.SUNDAY || firstDayOfWeek == Calendar.SATURDAY) {
322
+ add(DayOfWeek.SUNDAY)
323
+ }
324
+ add(DayOfWeek.MONDAY)
325
+ add(DayOfWeek.TUESDAY)
326
+ add(DayOfWeek.WEDNESDAY)
327
+ add(DayOfWeek.THURSDAY)
328
+ add(DayOfWeek.FRIDAY)
329
+ if (firstDayOfWeek != Calendar.SATURDAY) {
330
+ add(DayOfWeek.SATURDAY)
331
+ }
332
+ if (firstDayOfWeek != Calendar.SUNDAY && firstDayOfWeek != Calendar.SATURDAY) {
333
+ add(DayOfWeek.SUNDAY)
334
+ }
335
+ }
336
+
337
+ /**
338
+ * Return the number of days between the current day of the week and the previous day of the week.
339
+ *
340
+ * Example: If the current day of the week is MONDAY and the previous day of the week is FRIDAY, then it would
341
+ * return 3 because we have to go through SUNDAY, SATURDAY to FRIDAY.
342
+ *
343
+ * @param currentDay The current day of the week.
344
+ * @param previousDay The previous day of the week.
345
+ * @return Number of days between the current day of the week and the previous day of the week.
346
+ */
347
+ fun daysToPreviousDay(
348
+ currentDay: DayOfWeek,
349
+ previousDay: DayOfWeek,
350
+ ): PreviousDays {
351
+ if (currentDay == previousDay) {
352
+ return PreviousDays(0, false)
353
+ }
354
+ var indexCurrentDay = days.indexOf(currentDay)
355
+ var daysToPreviousDay = 0
356
+ var wasInPreviousWeek = false
357
+ while (true) {
358
+ indexCurrentDay -= 1
359
+ if (indexCurrentDay < 0) {
360
+ wasInPreviousWeek = true
361
+ indexCurrentDay = days.size - 1
362
+ }
363
+ daysToPreviousDay += 1
364
+
365
+ if (days[indexCurrentDay] == previousDay) {
366
+ break
367
+ }
368
+ }
369
+
370
+ return PreviousDays(daysToPreviousDay, wasInPreviousWeek)
371
+ }
372
+
373
+ class PreviousDays(
374
+ val daysToPreviousDay: Int,
375
+ val wasInPreviousWeek: Boolean,
376
+ )
377
+ }
@@ -0,0 +1,31 @@
1
+ package com.dayoneapp.mediastorage
2
+
3
+ import android.graphics.Bitmap
4
+
5
+ @JvmInline
6
+ value class CompressQuality(
7
+ val value: Int,
8
+ ) {
9
+ init {
10
+ require(value in 1..100) { }
11
+ }
12
+ }
13
+
14
+ class MediaStorageConfiguration(
15
+ val mediaPath: String,
16
+ val externalImagesPath: String,
17
+ val externalVideosPath: String,
18
+ val externalAudiosPath: String,
19
+ val externalDocumentsPath: String,
20
+ val avatarsPath: String,
21
+ val thumbnailsConfiguration: ThumbnailsConfiguration,
22
+ )
23
+
24
+ class ThumbnailsConfiguration(
25
+ val thumbnailsPath: String,
26
+ val height: Int,
27
+ val width: Int,
28
+ val extension: String,
29
+ val compression: Bitmap.CompressFormat,
30
+ val quality: CompressQuality,
31
+ )
@@ -0,0 +1,15 @@
1
+ package com.dayoneapp.dayone.utils
2
+
3
+ enum class AccountType(
4
+ val key: String,
5
+ ) {
6
+ DAY_ONE("Day One"),
7
+ GOOGLE("Google"),
8
+ APPLE("Apple ID"),
9
+ ;
10
+
11
+ companion object {
12
+ @JvmStatic
13
+ fun fromString(key: String): AccountType = values().find { it.key == key }!!
14
+ }
15
+ }
@@ -0,0 +1,76 @@
1
+ package com.dayoneapp.dayone.utils.usecase
2
+
3
+ import android.content.Context
4
+ import android.content.Intent
5
+ import androidx.activity.result.ActivityResultLauncher
6
+ import androidx.activity.result.contract.ActivityResultContracts.GetContent
7
+ import androidx.activity.result.contract.ActivityResultContracts.GetMultipleContents
8
+ import androidx.fragment.app.Fragment
9
+ import com.dayoneapp.dayone.utils.UriWrapper
10
+ import kotlinx.coroutines.flow.MutableSharedFlow
11
+ import kotlinx.coroutines.flow.asSharedFlow
12
+ import javax.inject.Inject
13
+
14
+ class SelectPhotoUseCase
15
+ @Inject
16
+ constructor() {
17
+ private lateinit var getContent: ActivityResultLauncher<String>
18
+ private val _mediaUris = MutableSharedFlow<List<UriWrapper>>(extraBufferCapacity = 5)
19
+ val mediaUris = _mediaUris.asSharedFlow()
20
+
21
+ fun onCreate(
22
+ fragment: Fragment,
23
+ singlePhoto: Boolean = false,
24
+ ) {
25
+ getContent =
26
+ if (singlePhoto) {
27
+ fragment.registerForActivityResult(GetSingleImage()) { uri ->
28
+ uri?.let {
29
+ _mediaUris.tryEmit(listOf(UriWrapper(it)))
30
+ }
31
+ }
32
+ } else {
33
+ fragment.registerForActivityResult(GetMultipleImages()) { uris ->
34
+ _mediaUris.tryEmit(uris.map { UriWrapper(it) })
35
+ }
36
+ }
37
+ }
38
+
39
+ fun selectPhotos() {
40
+ getContent.launch("image/*")
41
+ }
42
+
43
+ private class GetMultipleImages : GetMultipleContents() {
44
+ // Required to remove a lint error due to this method no longer calling super.createIntent()
45
+ @Suppress("MissingSuperCall")
46
+ override fun createIntent(
47
+ context: Context,
48
+ input: String,
49
+ ): Intent =
50
+ Intent(
51
+ Intent.ACTION_PICK,
52
+ android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
53
+ ).setType(input)
54
+ .putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
55
+ .apply {
56
+ putExtra(Intent.EXTRA_MIME_TYPES, arrayOf("image/jpeg", "image/png", "image/jpg"))
57
+ }
58
+ }
59
+
60
+ private class GetSingleImage : GetContent() {
61
+ // Required to remove a lint error due to this method no longer calling super.createIntent()
62
+ @Suppress("MissingSuperCall")
63
+ override fun createIntent(
64
+ context: Context,
65
+ input: String,
66
+ ): Intent =
67
+ Intent(
68
+ Intent.ACTION_PICK,
69
+ android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
70
+ ).setType(input)
71
+ .apply {
72
+ putExtra(Intent.EXTRA_MIME_TYPES, arrayOf("image/jpeg", "image/png", "image/jpg"))
73
+ }
74
+ }
75
+ }
76
+
@@ -72,19 +72,19 @@ module Danger
72
72
  end
73
73
 
74
74
  context 'when fail on error is false and a custom message is given' do
75
- include_examples 'reporting diff size custom warnings or errors', false, 'this is my custom warning message'
75
+ it_behaves_like 'reporting diff size custom warnings or errors', false, 'this is my custom warning message'
76
76
  end
77
77
 
78
78
  context 'when fail on error is false' do
79
- include_examples 'reporting diff size custom warnings or errors', false
79
+ it_behaves_like 'reporting diff size custom warnings or errors', false
80
80
  end
81
81
 
82
82
  context 'when fail on error is true' do
83
- include_examples 'reporting diff size custom warnings or errors', true
83
+ it_behaves_like 'reporting diff size custom warnings or errors', true
84
84
  end
85
85
 
86
86
  context 'when a custom error message is given and fail on error is true' do
87
- include_examples 'reporting diff size custom warnings or errors', true, 'this is my custom error message'
87
+ it_behaves_like 'reporting diff size custom warnings or errors', true, 'this is my custom error message'
88
88
  end
89
89
  end
90
90
  end
@@ -163,18 +163,18 @@ module Danger
163
163
  end
164
164
 
165
165
  context 'with the entire diff' do
166
- include_examples 'using the default diff size counter, without a file selector', :all
167
- include_examples 'using a file selector to filter and count the changes in a diff', :all, [422, 520, 1541]
166
+ it_behaves_like 'using the default diff size counter, without a file selector', :all
167
+ it_behaves_like 'using a file selector to filter and count the changes in a diff', :all, [422, 520, 1541]
168
168
  end
169
169
 
170
170
  context 'with the insertions in the diff' do
171
- include_examples 'using the default diff size counter, without a file selector', :insertions
172
- include_examples 'using a file selector to filter and count the changes in a diff', :insertions, [200, 139, 384]
171
+ it_behaves_like 'using the default diff size counter, without a file selector', :insertions
172
+ it_behaves_like 'using a file selector to filter and count the changes in a diff', :insertions, [200, 139, 384]
173
173
  end
174
174
 
175
175
  context 'with the deletions in the diff' do
176
- include_examples 'using the default diff size counter, without a file selector', :deletions
177
- include_examples 'using a file selector to filter and count the changes in a diff', :deletions, [221, 380, 1157]
176
+ it_behaves_like 'using the default diff size counter, without a file selector', :deletions
177
+ it_behaves_like 'using a file selector to filter and count the changes in a diff', :deletions, [221, 380, 1157]
178
178
  end
179
179
  end
180
180
 
@@ -221,19 +221,19 @@ module Danger
221
221
  end
222
222
 
223
223
  context 'when fail on error is false and a custom message is given' do
224
- include_examples 'reporting PR length check custom warnings or errors', false, 'this is my custom warning message'
224
+ it_behaves_like 'reporting PR length check custom warnings or errors', false, 'this is my custom warning message'
225
225
  end
226
226
 
227
227
  context 'when fail on error is false' do
228
- include_examples 'reporting PR length check custom warnings or errors', false
228
+ it_behaves_like 'reporting PR length check custom warnings or errors', false
229
229
  end
230
230
 
231
231
  context 'when fail on error is true' do
232
- include_examples 'reporting PR length check custom warnings or errors', true
232
+ it_behaves_like 'reporting PR length check custom warnings or errors', true
233
233
  end
234
234
 
235
235
  context 'when a custom error message is given and fail on error is true' do
236
- include_examples 'reporting PR length check custom warnings or errors', true, 'this is my custom error message'
236
+ it_behaves_like 'reporting PR length check custom warnings or errors', true, 'this is my custom error message'
237
237
  end
238
238
  end
239
239
  end
data/spec/spec_helper.rb CHANGED
@@ -58,8 +58,14 @@ def testing_dangerfile
58
58
  Danger::Dangerfile.new(env, testing_ui)
59
59
  end
60
60
 
61
- def fixture(name)
62
- File.read("spec/fixtures/#{name}")
61
+ # Returns the full path of the fixture at the given subpath (relative to `spec/fixtures`)
62
+ def fixture_path(*path_components)
63
+ File.join('spec', 'fixtures', *path_components)
64
+ end
65
+
66
+ # Returns the content of the fixture at the given path (relative to `spec/fixtures`)
67
+ def fixture(*path_components)
68
+ File.read(fixture_path(*path_components))
63
69
  end
64
70
 
65
71
  # custom matchers