@@ -2,6 +2,7 @@ package ai.elimu.content_provider.ui.image
2
2
3
3
import ai.elimu.content_provider.BaseApplication
4
4
import ai.elimu.content_provider.R
5
+ import ai.elimu.content_provider.databinding.FragmentImagesBinding
5
6
import ai.elimu.content_provider.rest.ImagesService
6
7
import ai.elimu.content_provider.room.GsonToRoomConverter
7
8
import ai.elimu.content_provider.room.db.RoomDb
@@ -14,55 +15,49 @@ import android.util.Log
14
15
import android.view.LayoutInflater
15
16
import android.view.View
16
17
import android.view.ViewGroup
17
- import android.widget.ProgressBar
18
- import android.widget.TextView
19
18
import androidx.fragment.app.Fragment
20
- import androidx.lifecycle.Observer
21
19
import androidx.lifecycle.ViewModelProvider
22
20
import com.google.android.material.snackbar.Snackbar
21
+ import kotlinx.coroutines.CoroutineScope
22
+ import kotlinx.coroutines.Dispatchers
23
+ import kotlinx.coroutines.launch
24
+ import kotlinx.coroutines.withContext
23
25
import retrofit2.Call
24
26
import retrofit2.Callback
25
27
import retrofit2.Response
26
28
import java.io.FileNotFoundException
27
29
import java.io.FileOutputStream
28
30
import java.io.IOException
29
- import java.util.concurrent.Executors
30
31
31
32
class ImagesFragment : Fragment () {
32
- private var imagesViewModel: ImagesViewModel ? = null
33
+ private lateinit var imagesViewModel: ImagesViewModel
33
34
34
- private var progressBar: ProgressBar ? = null
35
-
36
- private var textView: TextView ? = null
35
+ private lateinit var binding: FragmentImagesBinding
37
36
38
37
private val TAG = ImagesFragment ::class .java.name
39
38
40
39
override fun onCreateView (
41
40
inflater : LayoutInflater ,
42
41
container : ViewGroup ? ,
43
42
savedInstanceState : Bundle ?
44
- ): View ? {
43
+ ): View {
45
44
Log .i(TAG , " onCreateView" )
46
45
47
- imagesViewModel = ViewModelProvider (this ).get(ImagesViewModel ::class .java)
48
- val root = inflater.inflate(R .layout.fragment_images, container, false )
49
- progressBar = root.findViewById(R .id.progress_bar_images)
50
- textView = root.findViewById(R .id.text_images) as ? TextView
51
- imagesViewModel!! .text.observe(viewLifecycleOwner, object : Observer <String ?> {
52
- override fun onChanged (s : String? ) {
53
- Log .i(TAG , " onChanged" )
54
- textView?.text = s
55
- }
56
- })
57
- return root
46
+ imagesViewModel = ViewModelProvider (this )[ImagesViewModel ::class .java]
47
+ binding = FragmentImagesBinding .inflate(layoutInflater)
48
+ imagesViewModel.text.observe(viewLifecycleOwner) { s ->
49
+ Log .i(TAG , " onChanged" )
50
+ binding.textImages.text = s
51
+ }
52
+ return binding.root
58
53
}
59
54
60
55
override fun onStart () {
61
56
Log .i(TAG , " onStart" )
62
57
super .onStart()
63
58
64
59
// Download Images from REST API, and store them in the database
65
- val baseApplication = activity!! .application as BaseApplication
60
+ val baseApplication = activity? .application as ? BaseApplication ? : return
66
61
val retrofit = baseApplication.retrofit
67
62
val imagesService = retrofit.create(ImagesService ::class .java)
68
63
val imageGsonsCall = imagesService.listImages()
@@ -76,18 +71,18 @@ class ImagesFragment : Fragment() {
76
71
77
72
Log .i(TAG , " response: $response " )
78
73
if (response.isSuccessful) {
79
- val imageGsons = response.body()!!
74
+ val imageGsons = response.body() ? : return
80
75
Log .i(TAG , " imageGsons.size(): " + imageGsons.size)
81
76
82
- if (imageGsons.size > 0 ) {
77
+ if (imageGsons.isNotEmpty() ) {
83
78
processResponseBody(imageGsons)
84
79
}
85
80
} else {
86
81
// Handle error
87
- Snackbar .make(textView !! , response.toString(), Snackbar .LENGTH_LONG )
82
+ Snackbar .make(binding.textImages , response.toString(), Snackbar .LENGTH_LONG )
88
83
.setBackgroundTint(resources.getColor(R .color.deep_orange_darken_4))
89
84
.show()
90
- progressBar !! .visibility = View .GONE
85
+ binding.progressBarImages .visibility = View .GONE
91
86
}
92
87
}
93
88
@@ -97,93 +92,90 @@ class ImagesFragment : Fragment() {
97
92
Log .e(TAG , " t.getCause():" , t.cause)
98
93
99
94
// Handle error
100
- Snackbar .make(textView !! , t.cause.toString(), Snackbar .LENGTH_LONG )
95
+ Snackbar .make(binding.textImages , t.cause.toString(), Snackbar .LENGTH_LONG )
101
96
.setBackgroundTint(resources.getColor(R .color.deep_orange_darken_4))
102
97
.show()
103
- progressBar !! .visibility = View .GONE
98
+ binding.progressBarImages .visibility = View .GONE
104
99
}
105
100
})
106
101
}
107
102
108
103
private fun processResponseBody (imageGsons : List <ImageGson >) {
109
104
Log .i(TAG , " processResponseBody" )
110
105
111
- val executorService = Executors .newSingleThreadExecutor()
112
- executorService.execute(object : Runnable {
113
- override fun run () {
114
- Log .i(TAG , " run" )
115
-
116
- val roomDb = RoomDb .getDatabase(context)
117
- val imageDao = roomDb.imageDao()
118
- val image_WordDao = roomDb.image_WordDao()
119
-
120
- // Empty the database table before downloading up-to-date content
121
- image_WordDao.deleteAll()
122
- imageDao.deleteAll()
123
-
124
- // TODO: also delete corresponding image files (only those that are no longer used)
125
- for (imageGson in imageGsons) {
126
- Log .i(TAG , " imageGson.getId(): " + imageGson.id)
127
-
128
- val image = GsonToRoomConverter .getImage(imageGson)
129
-
130
- // Check if the corresponding image file has already been downloaded
131
- val imageFile = FileHelper .getImageFile(imageGson, context)
132
- Log .i(TAG , " imageFile: $imageFile " )
133
- Log .i(TAG , " imageFile.exists(): " + imageFile.exists())
134
- if (! imageFile.exists()) {
135
- // Download file bytes
136
- val baseApplication = activity!! .application as BaseApplication
137
- val downloadUrl = if (imageGson.bytesUrl.startsWith(" http" ))
138
- imageGson.bytesUrl
139
- else
140
- baseApplication.baseUrl + imageGson.bytesUrl
141
- Log .i(TAG , " downloadUrl: $downloadUrl " )
142
- val bytes = MultimediaDownloader .downloadFileBytes(downloadUrl)
143
- Log .i(TAG , " bytes.length: " + bytes.size)
144
-
145
- // Store the downloaded file in the external storage directory
146
- try {
147
- val fileOutputStream = FileOutputStream (imageFile)
148
- fileOutputStream.write(bytes)
149
- } catch (e: FileNotFoundException ) {
150
- Log .e(TAG , null , e)
151
- } catch (e: IOException ) {
152
- Log .e(TAG , null , e)
153
- }
154
- Log .i(TAG , " imageFile.exists(): " + imageFile.exists())
155
- }
156
-
157
- // Store the Image in the database
158
- imageDao.insert(image)
159
- Log .i(TAG , " Stored Image in database with ID " + image.id)
160
-
161
- // Store all the Image's Word labels in the database
162
- val wordGsons = imageGson.words
163
- Log .i(TAG , " wordGsons.size(): " + wordGsons.size)
164
- for (wordGson in wordGsons) {
165
- Log .i(TAG , " wordGson.getId(): " + wordGson.id)
166
- val image_Word = Image_Word ()
167
- image_Word.image_id = imageGson.id
168
- image_Word.words_id = wordGson.id
169
- image_WordDao.insert(image_Word)
170
- Log .i(
171
- TAG ,
172
- " Stored Image_Word in database. Image_id: " + image_Word.image_id + " , words_id: " + image_Word.words_id
173
- )
106
+ CoroutineScope (Dispatchers .IO ).launch {
107
+ Log .i(TAG , " run" )
108
+
109
+ val roomDb = RoomDb .getDatabase(context)
110
+ val imageDao = roomDb.imageDao()
111
+ val image_WordDao = roomDb.image_WordDao()
112
+
113
+ // Empty the database table before downloading up-to-date content
114
+ image_WordDao.deleteAll()
115
+ imageDao.deleteAll()
116
+
117
+ // TODO: also delete corresponding image files (only those that are no longer used)
118
+ for (imageGson in imageGsons) {
119
+ Log .i(TAG , " imageGson.getId(): " + imageGson.id)
120
+
121
+ val image = GsonToRoomConverter .getImage(imageGson)
122
+
123
+ // Check if the corresponding image file has already been downloaded
124
+ val imageFile = FileHelper .getImageFile(imageGson, context)
125
+ Log .i(TAG , " imageFile: $imageFile " )
126
+ Log .i(TAG , " imageFile.exists(): " + imageFile.exists())
127
+ if (! imageFile.exists()) {
128
+ // Download file bytes
129
+ val baseApplication = activity?.application as ? BaseApplication ? : return @launch
130
+ val downloadUrl = if (imageGson.bytesUrl.startsWith(" http" ))
131
+ imageGson.bytesUrl
132
+ else
133
+ baseApplication.baseUrl + imageGson.bytesUrl
134
+ Log .i(TAG , " downloadUrl: $downloadUrl " )
135
+ val bytes = MultimediaDownloader .downloadFileBytes(downloadUrl)
136
+ Log .i(TAG , " bytes.length: " + bytes.size)
137
+
138
+ // Store the downloaded file in the external storage directory
139
+ try {
140
+ val fileOutputStream = FileOutputStream (imageFile)
141
+ fileOutputStream.write(bytes)
142
+ } catch (e: FileNotFoundException ) {
143
+ Log .e(TAG , null , e)
144
+ } catch (e: IOException ) {
145
+ Log .e(TAG , null , e)
174
146
}
147
+ Log .i(TAG , " imageFile.exists(): " + imageFile.exists())
175
148
}
176
149
177
- // Update the UI
178
- val images = imageDao.loadAll()
179
- Log .i(TAG , " images.size(): " + images.size)
180
- activity!! .runOnUiThread {
181
- textView!! .text = " images.size(): " + images.size
182
- Snackbar .make(textView!! , " images.size(): " + images.size, Snackbar .LENGTH_LONG )
183
- .show()
184
- progressBar!! .visibility = View .GONE
150
+ // Store the Image in the database
151
+ imageDao.insert(image)
152
+ Log .i(TAG , " Stored Image in database with ID " + image.id)
153
+
154
+ // Store all the Image's Word labels in the database
155
+ val wordGsons = imageGson.words
156
+ Log .i(TAG , " wordGsons.size(): " + wordGsons.size)
157
+ for (wordGson in wordGsons) {
158
+ Log .i(TAG , " wordGson.getId(): " + wordGson.id)
159
+ val image_Word = Image_Word ()
160
+ image_Word.image_id = imageGson.id
161
+ image_Word.words_id = wordGson.id
162
+ image_WordDao.insert(image_Word)
163
+ Log .i(
164
+ TAG ,
165
+ " Stored Image_Word in database. Image_id: " + image_Word.image_id + " , words_id: " + image_Word.words_id
166
+ )
185
167
}
186
168
}
187
- })
169
+
170
+ // Update the UI
171
+ val images = imageDao.loadAll()
172
+ Log .i(TAG , " images.size(): " + images.size)
173
+ withContext(Dispatchers .Main ) {
174
+ binding.textImages.text = " images.size(): " + images.size
175
+ Snackbar .make(binding.textImages, " images.size(): " + images.size, Snackbar .LENGTH_LONG )
176
+ .show()
177
+ binding.progressBarImages.visibility = View .GONE
178
+ }
179
+ }
188
180
}
189
181
}
0 commit comments