These past two weeks, I have made a lot of progress on my GSoC project, I have:
- Fixed minor issues that were remaining in the room directory
- Reintroduced a third party protocol selection in the room directory search options as an easy solution to the issue I’ve talked about in my previous blogpost
- Implemented a new image viewer (that will be later used as a viewer for any media: videos, documents, etc…).
I will talk more about the image viewer in this post.
The initial issue
The initial issue was about improving how images were handled within Fractal: Fractal was using the `xdg-open` command in order to ask you which application you would like to use to open an image. So it looked like this:
Further more, because the media are downloaded into the folder `~/.cache/fractal` under their hash name before calling `xdg-open`, there are two major problems:
- The names given to the pictures have no sens at all (in “Select an application to open […]”)
- If you use “Eye of GNOME” to open this image, you will end up navigating among all the images contained into the Fractal’s cache folder where there are avatars and thumbnails from the current and other rooms which is absolutely not what we would want to have
So many solutions has been mentioned over the past months, I had tried to implement a simple dialog that was showing the image with three simple action: display the image in its real size, make the image fit inside the dialog and download the image. My prototype can be seen on this branch.
The media viewer wouldn’t be a separate dialog but it would be integrated within the main application window, just like the room directory. There would be a zoom entry that would enable the user to scale the image up and down, a button to enter in full screen mode and an overflow menu that would show other operations such as downloading the image.
How I have implemented it
I first implemented the design of the media viewer with Glade and then integrated it within the two
GtkStacks of the main window. There is a stack named `headerbar_stack` for the different header bars used by Fractal and a `main_content_stack` for the different window contents. The elements of the stacks to show are determined depending on the internal state of the application, so I created a new `MediaViewer` state that would show the header bar and the viewer that I implemented with Glade. When the user clicks on an image in a room, the program enters in this state and when they clicks on the back button of the media viewer, it goes back to the chat view. You can view these changes in this commit.
Next I implemented the ability to display the clicked image in the media viewer. I’ve used the Image custom widget but there was a big issue: the
Imagewidget needed to be passed a maximum size for the
GtkDrawingArea but (for an reason I couldn’t understand) the allocated size (width, height) of the
GtkViewport in which the
Image widget would be placed into was always of (1, 1), so it wasn’t usable to build the
Image widget. So I had to make the size argument optional and then it worked fine.
Next I implemented the ability to navigate in the pictures available in a room. For this, I created a new
MediaViewer struct that holds two field:
media_urlsthat is a
Vec<String>that holds the URLs of the media (for now just the pictures) currently loaded in the room.
current_url_indexthat is a
usizethat allows us to know the position of the URL (within
media_urls) of the media currently viewed.
Then in order to go to the previous/next media, we decrease/increase by one the value of
current_url_index and then we load the image with the URL
media_urls[current_url_index]. You can view the commit here.
The image was displayed but it wasn’t centered, it was at the top-left corner of the
GtkViewport. For some reasons (probably related to the allocated size issue), I couldn’t use methods such as
set_halign in order to center the
Imagewidget. So I had to implement a work around in which I would set up a custom origin when drawing the image on the
GtkDrawingAreain order to have it centered.
Implementing the ability to zoom in and out on the image took me quite much time. I first implemented the ability to enter an arbitrary zoom level to view the image and then Implemented the behavior of the “zoom out” and “zoom in” buttons so that they would request predefined zoom levels. See this commit for more details about it.
The title bar of the media viewer must be changed according to the media’s file name. This was rather easy to implement: I just needed to add a field
MediaViewerstruct, it was easy to fill as media names are store in the
body field of the media’s message, finally we set the title bar’s text with
media_names[current_media_index](the name of the index was changed from “current_url_index” to “current_media_index” in this commit). You can see the full details here.
Finally, I implemented the full screen mode of the viewer: when the user clicks on the full screen button in the header bar, it enters in the full screen mode and in order to exit this mode, the viewer can press escape. It has been implemented in this commit.
Here is the final result of the image viewer I’ve made:
What can still be improved
There are however some things that are yet to be improved:
- The buttons to zoom in and out are always sensitive: one of them should be insensitive when we are at the maximum/minimum zoom level.
- The zoom percentage input entry is a little bit messy.
- The image is not resized when entering in full screen mode.
- You cannot go further back (with the previous button) in the media history than the loaded messages of the current room.
- You cannot zoom more than 100% of the image size
- When the image is larger than the viewport, the horizontal scroll isn’t always available.
I will open an issue and solve some of these problems before moving to the next task.