@@ -16,6 +16,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
1616import androidx.compose.foundation.layout.height
1717import androidx.compose.foundation.layout.padding
1818import androidx.compose.foundation.layout.size
19+ import androidx.compose.foundation.layout.statusBarsPadding
1920import androidx.compose.foundation.shape.RoundedCornerShape
2021import androidx.compose.foundation.text.BasicTextField
2122import androidx.compose.material3.Button
@@ -50,7 +51,8 @@ class MainActivity : ComponentActivity() {
5051 enableEdgeToEdge()
5152 setContent {
5253 AndroidLinkPreviewTheme {
53- val linkPreviewViewModel = ViewModelProvider (this @MainActivity)[LinkPreviewViewModel ::class .java]
54+ val linkPreviewViewModel =
55+ ViewModelProvider (this @MainActivity)[LinkPreviewViewModel ::class .java]
5456 Scaffold (modifier = Modifier .fillMaxSize()) { innerPadding ->
5557 LinkPreviewScreen (
5658 modifier = Modifier .padding(innerPadding), viewModel = linkPreviewViewModel
@@ -67,90 +69,140 @@ fun LinkPreviewScreen(modifier: Modifier = Modifier, viewModel: LinkPreviewViewM
6769 var url by remember { mutableStateOf(TextFieldValue (" " )) }
6870 val previewData = viewModel.linkPreviewData.collectAsState(null )
6971 val isLoading = viewModel.isLoading.collectAsState()
70-
71- Column (
72- modifier = modifier
73- .fillMaxSize()
74- .padding(16 .dp),
75- verticalArrangement = Arrangement .Top ,
76- horizontalAlignment = Alignment .CenterHorizontally
77- ) {
72+ var errorMessage by remember { mutableStateOf<String ?>(null ) }
73+ Box (modifier = Modifier .fillMaxSize()) {
7874 Text (
7975 text = " Link Preview" ,
8076 style = MaterialTheme .typography.headlineLarge,
81- modifier = Modifier .padding(bottom = 16 .dp)
82- )
83- Text (
84- text = " Enter a URL to preview" ,
85- style = MaterialTheme .typography.bodyMedium,
86- modifier = Modifier .padding(bottom = 16 .dp)
87- )
88- BasicTextField (
89- value = url,
90- onValueChange = { url = it },
9177 modifier = Modifier
92- .fillMaxWidth()
93- .padding(8 .dp)
94- .background(Color .LightGray , RoundedCornerShape (8 .dp))
95- .padding(12 .dp)
78+ .padding(vertical = 16 .dp)
79+ .statusBarsPadding()
9680 )
97-
98- Button (
99- onClick = {
100- viewModel.fetchLinkPreviewData(url.text)
101- }, modifier = Modifier .padding(top = 8 .dp)
81+ Column (
82+ modifier = modifier
83+ .fillMaxSize()
84+ .padding(16 .dp),
85+ verticalArrangement = Arrangement .Center ,
86+ horizontalAlignment = Alignment .CenterHorizontally
10287 ) {
103- Text (" Submit" )
104- }
88+ Text (
89+ text = " Enter a URL to preview" ,
90+ style = MaterialTheme .typography.bodyMedium,
91+ modifier = Modifier
92+ .padding()
93+ .align(Alignment .Start )
94+ )
95+ Spacer (modifier = Modifier .height(8 .dp))
96+ BasicTextField (
97+ value = url,
98+ onValueChange = {
99+ url = it
100+ errorMessage = null
101+ },
102+ modifier = Modifier
103+ .fillMaxWidth()
104+ .background(Color .LightGray , RoundedCornerShape (8 .dp))
105+ .padding(12 .dp)
106+ )
105107
106- Spacer (modifier = Modifier .height(24 .dp))
108+ errorMessage?.let {
109+ Text (
110+ text = it,
111+ color = Color .Red ,
112+ style = MaterialTheme .typography.bodySmall,
113+ modifier = Modifier
114+ .fillMaxWidth()
115+ .padding(top = 12 .dp)
116+ )
117+ }
107118
108- if (isLoading.value) {
109- Box (
110- modifier = Modifier
119+
120+ Button (
121+ onClick = {
122+ val finalUrl = url.text.trim()
123+ val formattedUrl = when {
124+ finalUrl.isBlank() -> {
125+ viewModel.fetchLinkPreviewData(" " )
126+ errorMessage = " URL cannot be empty."
127+ null
128+ }
129+
130+ finalUrl.startsWith(" http://" ) -> {
131+ errorMessage = " http:// URLs are not supported. Please use https://"
132+ null
133+ }
134+
135+ finalUrl.startsWith(" https://" ) -> finalUrl
136+ else -> " https://$finalUrl "
137+ }
138+
139+ if (formattedUrl != null ) {
140+ viewModel.fetchLinkPreviewData(formattedUrl)
141+ }
142+ }, modifier = Modifier
111143 .fillMaxWidth()
112- .height(100 .dp)
113- .placeholder(
114- visible = true , highlight = PlaceholderHighlight .shimmer(), // ✅ no deprecation
115- color = Color .Gray .copy(alpha = 0.3f ), shape = RoundedCornerShape (12 .dp)
116- ), contentAlignment = Alignment .Center
144+ .padding(top = 8 .dp)
117145 ) {
146+ Text (" Submit" )
147+ }
148+ Spacer (modifier = Modifier .height(16 .dp))
149+
150+ if (isLoading.value) {
118151 Box (
119152 modifier = Modifier
120- .fillMaxSize ()
121- .background( Color . Gray .copy(alpha = 0.3f ) )
122- )
123- }
124- } else {
125- previewData.value?. let {
126- Card (
127- modifier = Modifier .fillMaxWidth( ), shape = RoundedCornerShape ( 12 .dp)
153+ .fillMaxWidth ()
154+ .height( 100 .dp )
155+ .placeholder(
156+ visible = true ,
157+ highlight = PlaceholderHighlight .shimmer(), // ✅ no deprecation
158+ color = Color . Gray .copy(alpha = 0.3f ),
159+ shape = RoundedCornerShape ( 12 .dp)
160+ ), contentAlignment = Alignment . Center
128161 ) {
129- Log .d(" TAG" , " LinkPreviewScreen: " + it.imageUrl)
130- Row {
131- GlideImage (
132- model = it.imageUrl,
133- contentDescription = null ,
134- contentScale = ContentScale .Crop ,
135- modifier = Modifier
136- .size(100 .dp)
137- .background(color = Color .Gray )
138- )
139- Column (modifier = Modifier .padding(16 .dp)) {
140- Text (text = it.title ? : " No Title" , style = MaterialTheme .typography.titleMedium)
141- Spacer (modifier = Modifier .height(4 .dp))
142- Text (
143- text = it.description ? : " No Description" ,
144- style = MaterialTheme .typography.bodyMedium,
145- maxLines = 1 ,
146- overflow = TextOverflow .Ellipsis
162+ Box (
163+ modifier = Modifier
164+ .fillMaxSize()
165+ .background(Color .Gray .copy(alpha = 0.3f ))
166+ )
167+ }
168+ } else {
169+ previewData.value?.let {
170+ Card (
171+ modifier = Modifier .fillMaxWidth(), shape = RoundedCornerShape (12 .dp)
172+ ) {
173+ Log .d(" TAG" , " LinkPreviewScreen: " + it.imageUrl)
174+ Row {
175+ GlideImage (
176+ model = it.imageUrl,
177+ contentDescription = null ,
178+ contentScale = ContentScale .Crop ,
179+ modifier = Modifier
180+ .size(100 .dp)
181+ .background(color = Color .Gray )
147182 )
148- Spacer (modifier = Modifier .height(4 .dp))
149- Text (text = it.url ? : " No URL" , style = MaterialTheme .typography.labelSmall)
183+ Column (modifier = Modifier .padding(16 .dp)) {
184+ Text (
185+ text = it.title ? : " No Title" ,
186+ style = MaterialTheme .typography.titleMedium
187+ )
188+ Spacer (modifier = Modifier .height(4 .dp))
189+ Text (
190+ text = it.description ? : " No Description" ,
191+ style = MaterialTheme .typography.bodyMedium,
192+ maxLines = 1 ,
193+ overflow = TextOverflow .Ellipsis
194+ )
195+ Spacer (modifier = Modifier .height(4 .dp))
196+ Text (
197+ text = it.url ? : " No URL" ,
198+ style = MaterialTheme .typography.labelSmall
199+ )
200+ }
150201 }
151202 }
152203 }
153204 }
205+
154206 }
155207 }
156208}
0 commit comments