Skip to content

Commit 82c24ba

Browse files
authored
Add ability to search Stackoverflow (#24)
* feat: Add ability to search Stackoverflow * fix: Fix lint errors * fix: Ignore missing constraints error due to bug in Android lint
1 parent 72deb46 commit 82c24ba

File tree

6 files changed

+121
-37
lines changed

6 files changed

+121
-37
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.haroldadmin.whatthestack
2+
3+
import java.net.URLEncoder
4+
5+
fun generateStackoverflowSearchUrl(query: String): String {
6+
val baseUrl = "https://stackoverflow.com/search"
7+
val queryString = URLEncoder.encode(query, "utf-8")
8+
return "$baseUrl?q=$queryString"
9+
}

what-the-stack/src/main/java/com/haroldadmin/whatthestack/WhatTheStackActivity.kt

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import android.content.ClipData
44
import android.content.ClipboardManager
55
import android.content.Context
66
import android.content.Intent
7+
import android.net.Uri
78
import android.os.Bundle
89
import android.text.method.ScrollingMovementMethod
910
import android.view.View
@@ -31,11 +32,11 @@ class WhatTheStackActivity : AppCompatActivity() {
3132
setContentView(binding.root)
3233

3334
window.decorView.systemUiVisibility =
34-
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
35+
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
3536

3637
Insetter.builder()
37-
.applySystemWindowInsetsToPadding(Side.LEFT or Side.RIGHT or Side.TOP)
38-
.applyToView(findViewById(R.id.nestedScrollRoot))
38+
.applySystemWindowInsetsToPadding(Side.LEFT or Side.RIGHT or Side.TOP)
39+
.applyToView(findViewById(R.id.nestedScrollRoot))
3940

4041
val type = intent.getStringExtra(KEY_EXCEPTION_TYPE)
4142
val cause = intent.getStringExtra(KEY_EXCEPTION_CAUSE)
@@ -89,6 +90,17 @@ class WhatTheStackActivity : AppCompatActivity() {
8990
}
9091
}
9192
}
93+
94+
binding.searchStackoverflow.apply {
95+
setOnClickListener {
96+
val searchQuery = "$cause: $message"
97+
val searchIntent: Intent = Intent().apply {
98+
this.action = Intent.ACTION_VIEW
99+
this.data = Uri.parse(generateStackoverflowSearchUrl(searchQuery))
100+
}
101+
startActivity(searchIntent)
102+
}
103+
}
92104
}
93105

94106
private inline fun snackbar(messageProvider: () -> Int) {
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="24"
5+
android:viewportHeight="24"
6+
android:tint="?attr/colorControlNormal">
7+
<path
8+
android:fillColor="@android:color/white"
9+
android:pathData="M15.5,14h-0.79l-0.28,-0.27c1.2,-1.4 1.82,-3.31 1.48,-5.34 -0.47,-2.78 -2.79,-5 -5.59,-5.34 -4.23,-0.52 -7.79,3.04 -7.27,7.27 0.34,2.8 2.56,5.12 5.34,5.59 2.03,0.34 3.94,-0.28 5.34,-1.48l0.27,0.28v0.79l4.25,4.25c0.41,0.41 1.08,0.41 1.49,0 0.41,-0.41 0.41,-1.08 0,-1.49L15.5,14zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
10+
</vector>

what-the-stack/src/main/res/layout/activity_what_the_stack.xml

Lines changed: 71 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@
77
android:layout_height="match_parent"
88
android:fillViewport="true">
99

10-
<LinearLayout
10+
<androidx.constraintlayout.widget.ConstraintLayout
1111
android:layout_width="match_parent"
12-
android:layout_height="match_parent"
13-
android:orientation="vertical">
12+
android:layout_height="match_parent">
1413

1514
<androidx.appcompat.widget.AppCompatTextView
1615
android:id="@+id/header"
@@ -19,16 +18,23 @@
1918
android:layout_margin="16dp"
2019
android:text="@string/header_text"
2120
android:textAppearance="?attr/textAppearanceHeadline4"
22-
android:textColor="?attr/colorOnSurface" />
21+
android:textColor="?attr/colorOnSurface"
22+
app:layout_constraintEnd_toEndOf="parent"
23+
app:layout_constraintStart_toStartOf="parent"
24+
app:layout_constraintTop_toTopOf="parent" />
2325

2426
<androidx.appcompat.widget.AppCompatTextView
27+
android:id="@+id/exceptionMessageHeader"
2528
android:layout_width="match_parent"
2629
android:layout_height="wrap_content"
2730
android:layout_marginStart="16dp"
2831
android:layout_marginEnd="16dp"
2932
android:text="@string/explanation_text"
3033
android:textAppearance="?attr/textAppearanceBody1"
31-
android:textColor="?attr/colorOnSurface" />
34+
android:textColor="?attr/colorOnSurface"
35+
app:layout_constraintEnd_toEndOf="parent"
36+
app:layout_constraintStart_toStartOf="parent"
37+
app:layout_constraintTop_toBottomOf="@id/header" />
3238

3339
<androidx.appcompat.widget.AppCompatTextView
3440
android:id="@+id/exceptionName"
@@ -41,6 +47,9 @@
4147
android:fontFamily="monospace"
4248
android:text="@string/exception_name"
4349
android:textAppearance="?attr/textAppearanceBody1"
50+
app:layout_constraintEnd_toEndOf="parent"
51+
app:layout_constraintStart_toStartOf="parent"
52+
app:layout_constraintTop_toBottomOf="@id/exceptionMessageHeader"
4453
tools:text="Exception: java.lang.RuntimeException" />
4554

4655
<androidx.appcompat.widget.AppCompatTextView
@@ -54,6 +63,9 @@
5463
android:fontFamily="monospace"
5564
android:text="@string/exception_cause"
5665
android:textAppearance="?attr/textAppearanceBody1"
66+
app:layout_constraintEnd_toEndOf="parent"
67+
app:layout_constraintStart_toStartOf="parent"
68+
app:layout_constraintTop_toBottomOf="@id/exceptionName"
5769
tools:text="Cause: BecauseICanException" />
5870

5971
<androidx.appcompat.widget.AppCompatTextView
@@ -67,49 +79,72 @@
6779
android:fontFamily="monospace"
6880
android:text="@string/exception_message"
6981
android:textAppearance="?attr/textAppearanceBody1"
82+
app:layout_constraintEnd_toEndOf="parent"
83+
app:layout_constraintStart_toStartOf="parent"
84+
app:layout_constraintTop_toBottomOf="@id/exceptionCause"
7085
tools:text="Message: Because I Can" />
7186

87+
<androidx.constraintlayout.helper.widget.Flow
88+
android:id="@+id/actionsFlow"
89+
android:layout_width="0dp"
90+
android:layout_height="wrap_content"
91+
android:layout_margin="16dp"
92+
app:constraint_referenced_ids="copyStacktrace,shareStacktrace,launchApplication,searchStackoverflow"
93+
app:flow_horizontalAlign="center"
94+
app:flow_horizontalGap="4dp"
95+
app:flow_horizontalStyle="packed"
96+
app:flow_verticalStyle="packed"
97+
app:flow_wrapMode="chain"
98+
app:layout_constraintEnd_toEndOf="parent"
99+
app:layout_constraintStart_toStartOf="parent"
100+
app:layout_constraintTop_toBottomOf="@id/exceptionMessage" />
101+
102+
<!-- Ignore missing-constraints lint error because lint hasn't been updated-->
103+
<!-- for constraint layout Flow yet-->
72104
<com.google.android.material.button.MaterialButton
73105
android:id="@+id/copyStacktrace"
74-
style="@style/Widget.MaterialComponents.Button.OutlinedButton.Icon"
75-
android:layout_width="match_parent"
106+
style="@style/Widget.MaterialComponents.Button.TextButton.Icon"
107+
android:layout_width="wrap_content"
76108
android:layout_height="wrap_content"
77-
android:layout_marginStart="16dp"
78-
android:layout_marginTop="16dp"
79-
android:layout_marginEnd="16dp"
80-
android:layout_marginBottom="2dp"
81109
android:text="@string/copy_stacktrace"
82110
android:textColor="?attr/colorOnSurface"
83111
app:icon="@drawable/ic_outline_content_copy_24"
84-
app:iconTint="?attr/colorSecondary" />
112+
app:iconTint="?attr/colorSecondary"
113+
tools:ignore="MissingConstraints" />
85114

86115
<com.google.android.material.button.MaterialButton
87116
android:id="@+id/shareStacktrace"
88-
style="@style/Widget.MaterialComponents.Button.OutlinedButton.Icon"
89-
android:layout_width="match_parent"
117+
style="@style/Widget.MaterialComponents.Button.TextButton.Icon"
118+
android:layout_width="wrap_content"
90119
android:layout_height="wrap_content"
91-
android:layout_marginStart="16dp"
92-
android:layout_marginTop="2dp"
93-
android:layout_marginEnd="16dp"
94-
android:layout_marginBottom="2dp"
95120
android:text="@string/share_stacktrace"
96121
android:textColor="?attr/colorOnSurface"
97122
app:icon="@drawable/ic_outline_share_24"
98-
app:iconTint="?attr/colorSecondary" />
123+
app:iconTint="?attr/colorSecondary"
124+
tools:ignore="MissingConstraints" />
99125

100126
<com.google.android.material.button.MaterialButton
101127
android:id="@+id/launchApplication"
102-
style="@style/Widget.MaterialComponents.Button.OutlinedButton.Icon"
103-
android:layout_width="match_parent"
128+
style="@style/Widget.MaterialComponents.Button.TextButton.Icon"
129+
android:layout_width="wrap_content"
104130
android:layout_height="wrap_content"
105-
android:layout_marginStart="16dp"
106-
android:layout_marginTop="2dp"
107-
android:layout_marginEnd="16dp"
108-
android:layout_marginBottom="8dp"
109131
android:text="@string/restart_application"
110132
android:textColor="?attr/colorOnSurface"
111133
app:icon="@drawable/ic_baseline_refresh_24"
112-
app:iconTint="?attr/colorSecondary" />
134+
app:iconTint="?attr/colorSecondary"
135+
tools:ignore="MissingConstraints" />
136+
137+
<com.google.android.material.button.MaterialButton
138+
android:id="@+id/searchStackoverflow"
139+
style="@style/Widget.MaterialComponents.Button.TextButton.Icon"
140+
android:layout_width="wrap_content"
141+
android:layout_height="wrap_content"
142+
android:layout_margin="4dp"
143+
android:text="@string/search_stackoverflow"
144+
android:textColor="?attr/colorOnSurface"
145+
app:icon="@drawable/ic_round_search_24"
146+
app:iconTint="?attr/colorSecondary"
147+
tools:ignore="MissingConstraints" />
113148

114149
<TextView
115150
android:id="@+id/stacktraceHeader"
@@ -119,15 +154,21 @@
119154
android:layout_marginTop="8dp"
120155
android:layout_marginEnd="16dp"
121156
android:text="@string/stacktrace"
122-
android:textAppearance="?attr/textAppearanceOverline" />
157+
android:textAppearance="?attr/textAppearanceOverline"
158+
app:layout_constraintEnd_toEndOf="parent"
159+
app:layout_constraintStart_toStartOf="parent"
160+
app:layout_constraintTop_toBottomOf="@id/actionsFlow" />
123161

124162
<ScrollView
125163
android:id="@+id/stacktraceScroller"
126164
android:layout_width="match_parent"
127-
android:layout_height="match_parent"
165+
android:layout_height="0dp"
128166
android:layout_marginTop="4dp"
129167
android:paddingStart="16dp"
130-
android:paddingEnd="16dp">
168+
android:paddingEnd="16dp"
169+
app:layout_constraintEnd_toEndOf="parent"
170+
app:layout_constraintStart_toStartOf="parent"
171+
app:layout_constraintTop_toBottomOf="@id/stacktraceHeader">
131172

132173
<TextView
133174
android:id="@+id/stacktrace"
@@ -138,6 +179,5 @@
138179
android:textColor="?attr/colorError"
139180
tools:text="@string/sample_stack_trace" />
140181
</ScrollView>
141-
142-
</LinearLayout>
182+
</androidx.constraintlayout.widget.ConstraintLayout>
143183
</androidx.core.widget.NestedScrollView>

what-the-stack/src/main/res/values/strings.xml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,10 @@
3030
<string name="exception_cause">Cause: %1$s</string>
3131
<string name="stacktrace">Stacktrace</string>
3232
<string name="exception_message">Message: %1$s</string>
33-
<string name="copy_stacktrace">Copy stacktrace</string>
34-
<string name="share_stacktrace">Share stacktrace</string>
35-
<string name="restart_application">Restart Application</string>
33+
<string name="copy_stacktrace">Copy</string>
34+
<string name="share_stacktrace">Share</string>
35+
<string name="restart_application">Restart</string>
3636
<string name="relaunch_app">Relaunch App</string>
3737
<string name="copied_message">Stacktrace copied!</string>
38+
<string name="search_stackoverflow">Stackoverflow</string>
3839
</resources>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.haroldadmin.whatthestack
2+
3+
import org.junit.Test
4+
5+
internal class StackoverflowUrlTest {
6+
@Test
7+
fun shouldEncodeSearchStringCorrectly() {
8+
val searchQuery = "test search"
9+
val url = generateStackoverflowSearchUrl(searchQuery)
10+
assert(!url.contains(' '))
11+
}
12+
}

0 commit comments

Comments
 (0)