Skip to content

Commit ae47db8

Browse files
authored
Merge pull request #919 from synonymdev/feat/headlines-v61
2 parents 41ff9c9 + 7069e76 commit ae47db8

28 files changed

Lines changed: 1003 additions & 447 deletions

app/src/androidTest/java/to/bitkit/ui/screens/widgets/headlines/HeadlineCardTest.kt

Lines changed: 29 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,9 @@ class HeadlineCardTest {
1919

2020
@Test
2121
fun testHeadlineCardWithAllElements() {
22-
// Arrange & Act
2322
composeTestRule.setContent {
2423
AppThemeSurface {
2524
HeadlineCard(
26-
showWidgetTitle = true,
2725
showTime = true,
2826
showSource = true,
2927
time = testTime,
@@ -34,57 +32,21 @@ class HeadlineCardTest {
3432
}
3533
}
3634

37-
// Assert all elements exist
38-
composeTestRule.onNodeWithTag("widget_title_row", useUnmergedTree = true).assertExists()
39-
composeTestRule.onNodeWithTag("widget_title_icon", useUnmergedTree = true).assertExists()
40-
composeTestRule.onNodeWithTag("widget_title_text", useUnmergedTree = true).assertExists()
4135
composeTestRule.onNodeWithTag("time_text", useUnmergedTree = true).assertExists()
4236
composeTestRule.onNodeWithTag("headline_text", useUnmergedTree = true).assertExists()
4337
composeTestRule.onNodeWithTag("source_row", useUnmergedTree = true).assertExists()
44-
composeTestRule.onNodeWithTag("source_label", useUnmergedTree = true).assertExists()
4538
composeTestRule.onNodeWithTag("source_text", useUnmergedTree = true).assertExists()
4639

47-
// Verify text content
4840
composeTestRule.onNodeWithTag("time_text", useUnmergedTree = true).assertTextEquals(testTime)
4941
composeTestRule.onNodeWithTag("headline_text", useUnmergedTree = true).assertTextEquals(testHeadline)
5042
composeTestRule.onNodeWithTag("source_text", useUnmergedTree = true).assertTextEquals(testSource)
5143
}
5244

53-
@Test
54-
fun testHeadlineCardWithoutWidgetTitle() {
55-
// Arrange & Act
56-
composeTestRule.setContent {
57-
AppThemeSurface {
58-
HeadlineCard(
59-
showWidgetTitle = false,
60-
showTime = true,
61-
showSource = true,
62-
time = testTime,
63-
headline = testHeadline,
64-
source = testSource,
65-
link = testLink
66-
)
67-
}
68-
}
69-
70-
// Assert main elements exist
71-
composeTestRule.onNodeWithTag("time_text", useUnmergedTree = true).assertExists()
72-
composeTestRule.onNodeWithTag("headline_text", useUnmergedTree = true).assertExists()
73-
composeTestRule.onNodeWithTag("source_row", useUnmergedTree = true).assertExists()
74-
75-
// Assert widget title elements do not exist
76-
composeTestRule.onNodeWithTag("widget_title_row", useUnmergedTree = true).assertDoesNotExist()
77-
composeTestRule.onNodeWithTag("widget_title_icon", useUnmergedTree = true).assertDoesNotExist()
78-
composeTestRule.onNodeWithTag("widget_title_text", useUnmergedTree = true).assertDoesNotExist()
79-
}
80-
8145
@Test
8246
fun testHeadlineCardWithoutTime() {
83-
// Arrange & Act
8447
composeTestRule.setContent {
8548
AppThemeSurface {
8649
HeadlineCard(
87-
showWidgetTitle = true,
8850
showTime = false,
8951
showSource = true,
9052
time = testTime,
@@ -95,22 +57,18 @@ class HeadlineCardTest {
9557
}
9658
}
9759

98-
// Assert main elements exist
99-
composeTestRule.onNodeWithTag("widget_title_row", useUnmergedTree = true).assertExists()
10060
composeTestRule.onNodeWithTag("headline_text", useUnmergedTree = true).assertExists()
10161
composeTestRule.onNodeWithTag("source_row", useUnmergedTree = true).assertExists()
62+
composeTestRule.onNodeWithTag("source_text", useUnmergedTree = true).assertExists()
10263

103-
// Assert time element does not exist
10464
composeTestRule.onNodeWithTag("time_text", useUnmergedTree = true).assertDoesNotExist()
10565
}
10666

10767
@Test
10868
fun testHeadlineCardWithoutSource() {
109-
// Arrange & Act
11069
composeTestRule.setContent {
11170
AppThemeSurface {
11271
HeadlineCard(
113-
showWidgetTitle = true,
11472
showTime = true,
11573
showSource = false,
11674
time = testTime,
@@ -121,24 +79,17 @@ class HeadlineCardTest {
12179
}
12280
}
12381

124-
// Assert main elements exist
125-
composeTestRule.onNodeWithTag("widget_title_row", useUnmergedTree = true).assertExists()
12682
composeTestRule.onNodeWithTag("time_text", useUnmergedTree = true).assertExists()
12783
composeTestRule.onNodeWithTag("headline_text", useUnmergedTree = true).assertExists()
12884

129-
// Assert source elements do not exist
130-
composeTestRule.onNodeWithTag("source_row", useUnmergedTree = true).assertDoesNotExist()
131-
composeTestRule.onNodeWithTag("source_label", useUnmergedTree = true).assertDoesNotExist()
13285
composeTestRule.onNodeWithTag("source_text", useUnmergedTree = true).assertDoesNotExist()
13386
}
13487

13588
@Test
13689
fun testHeadlineCardMinimal() {
137-
// Arrange & Act - Only headline shown
13890
composeTestRule.setContent {
13991
AppThemeSurface {
14092
HeadlineCard(
141-
showWidgetTitle = false,
14293
showTime = false,
14394
showSource = false,
14495
time = testTime,
@@ -149,55 +100,45 @@ class HeadlineCardTest {
149100
}
150101
}
151102

152-
// Assert only essential elements exist
153103
composeTestRule.onNodeWithTag("headline_text", useUnmergedTree = true).assertExists()
154104

155-
// Assert optional elements do not exist
156-
composeTestRule.onNodeWithTag("widget_title_row", useUnmergedTree = true).assertDoesNotExist()
157105
composeTestRule.onNodeWithTag("time_text", useUnmergedTree = true).assertDoesNotExist()
158106
composeTestRule.onNodeWithTag("source_row", useUnmergedTree = true).assertDoesNotExist()
107+
composeTestRule.onNodeWithTag("source_text", useUnmergedTree = true).assertDoesNotExist()
159108

160-
// Verify headline text
161109
composeTestRule.onNodeWithTag("headline_text", useUnmergedTree = true).assertTextEquals(testHeadline)
162110
}
163111

164112
@Test
165113
fun testHeadlineCardWithEmptyTime() {
166-
// Arrange & Act - Time is empty string
167114
composeTestRule.setContent {
168115
AppThemeSurface {
169116
HeadlineCard(
170-
showWidgetTitle = true,
171117
showTime = true,
172118
showSource = true,
173-
time = "", // Empty time
119+
time = "",
174120
headline = testHeadline,
175121
source = testSource,
176122
link = testLink
177123
)
178124
}
179125
}
180126

181-
// Assert main elements exist
182-
composeTestRule.onNodeWithTag("widget_title_row", useUnmergedTree = true).assertExists()
183127
composeTestRule.onNodeWithTag("headline_text", useUnmergedTree = true).assertExists()
184128
composeTestRule.onNodeWithTag("source_row", useUnmergedTree = true).assertExists()
129+
composeTestRule.onNodeWithTag("source_text", useUnmergedTree = true).assertExists()
185130

186-
// Assert time element does not exist when time is empty
187131
composeTestRule.onNodeWithTag("time_text", useUnmergedTree = true).assertDoesNotExist()
188132
}
189133

190134
@Test
191135
fun testHeadlineCardWithLongHeadline() {
192-
// Arrange
193136
val longHeadline =
194137
"This is a very long headline that should be truncated because it exceeds the maximum number of lines allowed in the headline card component and should show ellipsis"
195138

196-
// Act
197139
composeTestRule.setContent {
198140
AppThemeSurface {
199141
HeadlineCard(
200-
showWidgetTitle = true,
201142
showTime = true,
202143
showSource = true,
203144
time = testTime,
@@ -208,35 +149,46 @@ class HeadlineCardTest {
208149
}
209150
}
210151

211-
// Assert headline exists and contains the text (may be truncated)
212152
composeTestRule.onNodeWithTag("headline_text", useUnmergedTree = true).assertExists()
213153
}
214154

215155
@Test
216-
fun testAllElementsExistInFullConfiguration() {
217-
// Arrange & Act
156+
fun testHeadlineCardSmallWithTime() {
218157
composeTestRule.setContent {
219158
AppThemeSurface {
220-
HeadlineCard(
221-
showWidgetTitle = true,
159+
HeadlineCardSmall(
222160
showTime = true,
223-
showSource = true,
224161
time = testTime,
225162
headline = testHeadline,
226-
source = testSource,
227163
link = testLink
228164
)
229165
}
230166
}
231167

232-
// Assert all tagged elements exist
233-
composeTestRule.onNodeWithTag("widget_title_row", useUnmergedTree = true).assertExists()
234-
composeTestRule.onNodeWithTag("widget_title_icon", useUnmergedTree = true).assertExists()
235-
composeTestRule.onNodeWithTag("widget_title_text", useUnmergedTree = true).assertExists()
236-
composeTestRule.onNodeWithTag("time_text", useUnmergedTree = true).assertExists()
237168
composeTestRule.onNodeWithTag("headline_text", useUnmergedTree = true).assertExists()
238169
composeTestRule.onNodeWithTag("source_row", useUnmergedTree = true).assertExists()
239-
composeTestRule.onNodeWithTag("source_label", useUnmergedTree = true).assertExists()
240-
composeTestRule.onNodeWithTag("source_text", useUnmergedTree = true).assertExists()
170+
composeTestRule.onNodeWithTag("time_text", useUnmergedTree = true).assertExists()
171+
172+
composeTestRule.onNodeWithTag("time_text", useUnmergedTree = true).assertTextEquals(testTime)
173+
composeTestRule.onNodeWithTag("headline_text", useUnmergedTree = true).assertTextEquals(testHeadline)
174+
}
175+
176+
@Test
177+
fun testHeadlineCardSmallWithoutTime() {
178+
composeTestRule.setContent {
179+
AppThemeSurface {
180+
HeadlineCardSmall(
181+
showTime = false,
182+
time = testTime,
183+
headline = testHeadline,
184+
link = testLink
185+
)
186+
}
187+
}
188+
189+
composeTestRule.onNodeWithTag("headline_text", useUnmergedTree = true).assertExists()
190+
191+
composeTestRule.onNodeWithTag("time_text", useUnmergedTree = true).assertDoesNotExist()
192+
composeTestRule.onNodeWithTag("source_row", useUnmergedTree = true).assertDoesNotExist()
241193
}
242194
}

app/src/androidTest/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesPreviewContentTest.kt

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ class HeadlinesPreviewContentTest {
4242
onClickEdit = { editClicked = true },
4343
onClickDelete = { deleteClicked = true },
4444
onClickSave = { saveClicked = true },
45-
showWidgetTitles = true,
4645
isHeadlinesImplemented = true,
4746
headlinePreferences = mockHeadlinePreferences,
4847
article = mockArticle
@@ -52,18 +51,12 @@ class HeadlinesPreviewContentTest {
5251

5352
// Assert main elements exist
5453
composeTestRule.onNodeWithTag("headlines_preview_screen").assertExists()
55-
composeTestRule.onNodeWithTag("main_content").assertExists()
56-
57-
// Verify header elements
58-
composeTestRule.onNodeWithTag("header_row").assertExists()
59-
composeTestRule.onNodeWithTag("widget_title").assertExists()
60-
composeTestRule.onNodeWithTag("widget_icon").assertExists()
6154
composeTestRule.onNodeWithTag("widget_description").assertExists()
6255

6356
// Verify settings and preview section
6457
composeTestRule.onNodeWithTag("WidgetEdit").assertExists()
65-
composeTestRule.onNodeWithTag("preview_label").assertExists()
66-
composeTestRule.onNodeWithTag("headline_card").assertExists()
58+
composeTestRule.onNodeWithTag("headlines_preview_carousel").assertExists()
59+
composeTestRule.onNodeWithTag("headline_card_small").assertExists()
6760

6861
// Verify buttons
6962
composeTestRule.onNodeWithTag("buttons_row").assertExists()
@@ -97,7 +90,6 @@ class HeadlinesPreviewContentTest {
9790
onClickEdit = { editClicked = true },
9891
onClickDelete = { deleteClicked = true },
9992
onClickSave = { saveClicked = true },
100-
showWidgetTitles = false,
10193
isHeadlinesImplemented = false,
10294
headlinePreferences = mockHeadlinePreferences,
10395
article = mockArticle
@@ -134,7 +126,6 @@ class HeadlinesPreviewContentTest {
134126
onClickEdit = {},
135127
onClickDelete = {},
136128
onClickSave = {},
137-
showWidgetTitles = true,
138129
isHeadlinesImplemented = true,
139130
headlinePreferences = customPreferences,
140131
article = mockArticle
@@ -145,7 +136,7 @@ class HeadlinesPreviewContentTest {
145136
// Assert that all elements still exist with custom preferences
146137
composeTestRule.onNodeWithTag("headlines_preview_screen").assertExists()
147138
composeTestRule.onNodeWithTag("WidgetEdit").assertExists()
148-
composeTestRule.onNodeWithTag("headline_card").assertExists()
139+
composeTestRule.onNodeWithTag("headlines_preview_carousel").assertExists()
149140
}
150141

151142
@Test
@@ -158,7 +149,6 @@ class HeadlinesPreviewContentTest {
158149
onClickEdit = {},
159150
onClickDelete = {},
160151
onClickSave = {},
161-
showWidgetTitles = true,
162152
isHeadlinesImplemented = true,
163153
headlinePreferences = mockHeadlinePreferences,
164154
article = mockArticle
@@ -168,15 +158,11 @@ class HeadlinesPreviewContentTest {
168158

169159
// Assert all tagged elements exist
170160
composeTestRule.onNodeWithTag("headlines_preview_screen").assertExists()
171-
composeTestRule.onNodeWithTag("main_content").assertExists()
172-
composeTestRule.onNodeWithTag("header_row").assertExists()
173-
composeTestRule.onNodeWithTag("widget_title").assertExists()
174-
composeTestRule.onNodeWithTag("widget_icon").assertExists()
175161
composeTestRule.onNodeWithTag("widget_description").assertExists()
176162
composeTestRule.onNodeWithTag("divider").assertExists()
177163
composeTestRule.onNodeWithTag("WidgetEdit").assertExists()
178-
composeTestRule.onNodeWithTag("preview_label").assertExists()
179-
composeTestRule.onNodeWithTag("headline_card").assertExists()
164+
composeTestRule.onNodeWithTag("headlines_preview_carousel").assertExists()
165+
composeTestRule.onNodeWithTag("headline_card_small").assertExists()
180166
composeTestRule.onNodeWithTag("buttons_row").assertExists()
181167
composeTestRule.onNodeWithTag("WidgetDelete").assertExists()
182168
composeTestRule.onNodeWithTag("WidgetSave").assertExists()
@@ -194,7 +180,6 @@ class HeadlinesPreviewContentTest {
194180
onClickEdit = {},
195181
onClickDelete = {},
196182
onClickSave = {},
197-
showWidgetTitles = true,
198183
isHeadlinesImplemented = true,
199184
headlinePreferences = mockHeadlinePreferences,
200185
article = mockArticle
@@ -219,7 +204,6 @@ class HeadlinesPreviewContentTest {
219204
onClickEdit = {},
220205
onClickDelete = {},
221206
onClickSave = {},
222-
showWidgetTitles = false,
223207
isHeadlinesImplemented = false,
224208
headlinePreferences = minimalPreferences,
225209
article = mockArticle
@@ -229,7 +213,7 @@ class HeadlinesPreviewContentTest {
229213

230214
// Assert core elements still exist
231215
composeTestRule.onNodeWithTag("headlines_preview_screen").assertExists()
232-
composeTestRule.onNodeWithTag("headline_card").assertExists()
216+
composeTestRule.onNodeWithTag("headlines_preview_carousel").assertExists()
233217
composeTestRule.onNodeWithTag("WidgetSave").assertExists()
234218
composeTestRule.onNodeWithTag("WidgetDelete").assertDoesNotExist()
235219
}

app/src/main/AndroidManifest.xml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,19 @@
204204
android:resource="@xml/appwidget_info_price" />
205205
</receiver>
206206

207+
<!-- Headlines Widget -->
208+
<receiver
209+
android:name=".appwidget.ui.headlines.HeadlinesGlanceReceiver"
210+
android:exported="true"
211+
android:label="@string/widgets__news__name">
212+
<intent-filter>
213+
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
214+
</intent-filter>
215+
<meta-data
216+
android:name="android.appwidget.provider"
217+
android:resource="@xml/appwidget_info_headlines" />
218+
</receiver>
219+
207220
</application>
208221

209222
</manifest>

app/src/main/java/to/bitkit/appwidget/AppWidgetDataRepository.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ package to.bitkit.appwidget
22

33
import kotlinx.coroutines.CoroutineDispatcher
44
import kotlinx.coroutines.withContext
5+
import to.bitkit.data.dto.ArticleDTO
56
import to.bitkit.data.dto.price.GraphPeriod
67
import to.bitkit.data.dto.price.PriceDTO
8+
import to.bitkit.data.widgets.NewsService
79
import to.bitkit.data.widgets.PriceService
810
import to.bitkit.di.IoDispatcher
911
import javax.inject.Inject
@@ -13,9 +15,15 @@ import javax.inject.Singleton
1315
class AppWidgetDataRepository @Inject constructor(
1416
@IoDispatcher private val ioDispatcher: CoroutineDispatcher,
1517
private val priceService: PriceService,
18+
private val newsService: NewsService,
1619
) {
1720
suspend fun fetchPriceData(period: GraphPeriod = GraphPeriod.ONE_DAY): Result<PriceDTO> =
1821
withContext(ioDispatcher) {
1922
priceService.fetchData(period)
2023
}
24+
25+
suspend fun fetchArticles(): Result<List<ArticleDTO>> =
26+
withContext(ioDispatcher) {
27+
newsService.fetchData()
28+
}
2129
}

0 commit comments

Comments
 (0)