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