GSoC 2024: Dashboard Page and Feed revamp in ListenBrainz iOS App for all users

Contact Information

Name: Gaurav

IRC nick: theflash_

Email: [redacted]

Github: gauravbhardwaj7

Time Zone: UTC+05:30

My name is Gaurav, I am currently a pre-final year student hailing from Chandigarh, India. I am an Information Technology engineering student and I specialise in iOS development using Swift language.I also have a keen interest for solving various problems using C++.

Also, I love to learn new frameworks, I am currently learning Machine Learning which is also a part of my University curriculum. I also love to read articles related to these technologies.

My hobbies include Cycling and Running. I have an immense love for music and Swift, which became a driving force for me to contribute in this project.

Dashboard Page and Feed revamp in ListenBrainz iOS App for all users

Project Overview

After huge success of Listenbrainz’s website and android app , we have Listenbrainz-iOS in the pipeline. As of now, beta is available on Testflight (testing service by Apple).

The project aims to seamlessly integrate a user dashboard into the app in which a user can not only see their own dashboard but others’ too and revamp the existing feed by adding features such as CritiqueBrainz review, pin, unpin, hide, unhide an event in the feed.

An important aspect of this project is to maintain the UI/UX alignment with figma design shared by the design team.

By completing this project, the ListenBrainz app will offer a comprehensive feed and dashboard feature for users, mirroring the website’s functionality. This includes displaying detailed music listening statistics, recent listens, top artists, and more, all within a user-friendly and engaging mobile interface.

Estimated Project Length: 350 hours

The detailed plan of action for implementing the user dashboard is explained in the following section.

My contributions in Metabrainz so far:

My Commits - Commits
My Pull requests - Pull requests

Current State of ListenBrainz-iOS

In the current state, the app offers:

  • Feed Section: contains basic feed
  • Explore Page: having Year In Music 2023
  • Player: Shazam feature
  • Listens history profile page
  • Settings page

Plan Of Action:

The plan of implementing is to be carried in the following phases -

Phase 1 - User Search and feed revamp

The first phase includes initial setup of things that are inevitable to make dashboard into action. The tasks included in this phase are -

1.) Implement Search Users - For adding search users functionality

  • Add a search bar component in the top bar adjacent to that of settings icon.

  • GET /1/search/users?search_term=<user_name> - Use this endpoint to get the list of all the users by changing the dynamic parameter in the search_term with the text entered by user in the search bar.

2.) Feed revamp - Modify listen card and add dialog

In the current state, our feed does not have the support for adding the support for adding the CritiqueBrainz review and there is no dialog.
So in this phase, a dialog containing following features can be added successfully using following endpoints -

  • GET /1/user/(user_name)/services* - used to find whether user has linked their CritiqueBrainz account or not,
  • POST /1/user/(user_name)/timeline-event/create/recording* - allows user to recommend a track to other users.
  • POST /1/user/(user_name)/timeline-event/create/review* - allows user to post a review of a track from within the app.
  • POST /1/pin* - allows user to pin a recording

Note - * on api represents LB token is inevitable.


Phase 2 - Dashboard Setup

This includes setting up repository, view model and model for the dashboard. This includes -

1.) Repository for dashboard

  • Make a protocol , let’s say DashboardRepository and make a function fetchDashboardData with parameter input as userName.

2.) Repository Implementation - Inside the repository implementation, networking requests will be handled using library Alamofire and handling of asynchronous operations will be managed using Combine.

3.) View model for dashboard -

For handling different states, SwiftData will be incorporated as it is more flexible in terms of handling models.

We could use query and environment macros for handling the data fetch but it’s difficult to write unit tests for it as query needs SwiftUI to be actively involved. So, we will be using MVVM approach.

To proceed with implementing MVVM architecture using SwiftData -

  • Create a view model using @ObservableObject macro and add parameters that needs to be reflected in UI in it. Using this macro is inevitable to reflect data fetch and when the data changes over time.
  • Create SwiftData models that conforms to @Model and use them in view model.
  • After that, call models and viewmodel in respective views.
class DashboardViewModel: ObservableObject {

    @Published var following: Int = 0
    @Published var totalListenCount: Int = 0
    @Published var followers: Int = 0

  // Add other properties that needs to be fetched here

        
    private var cancellables: Set<AnyCancellable> = []
    
    private let repository: DashboardRepository

    init(repository: DashboardRepository) {
        self.repository = repository
    }
    
  func fetchDashboardData(userName: String, userToken:String) {
      repository.fetchDashboardData(userName: userName,userToken: userToken)
            .receive(on: DispatchQueue.main)
            .sink { completion in
                switch completion {
                case .finished:
                    break
                case .failure(let error):
                    print("Error fetching dashboard data: \(error.localizedDescription)")
                }
            } receiveValue: { data in
                self.following = data.following // refrenced to following list in the model
                self.totalListenCount = data.payload.data.totalListenCount
                self.followers = data.followers

              // Add other required properties
            }

      
            .store(in: &cancellables)
    }
}

In view model,

  • fun fetchDashboardData fetches the data from the repository based on the given user name. It handles the asynchronous operation using Combine(library in SwiftUI)'s sink operator.

  • Published variables are used , which means any changes to this property will automatically notify any subscribers (such as dashboard views) about the change.

  • init(repository: DashboardRepository) : This is the initializer for the ViewModel. It takes a repository conforming to DashboardRepository as a parameter.

4.) Model for dashboard - After repository and view model setup, model is made. The following steps are involved-

  • Import SwiftData library for making the models.

  • Perform api request on a server and carefully examine the parameters that are required in the frontend.

  • Make structs according to the multiple JSON schema and use that in the view model.

// Sample model after running followers api request 
import Foundation
import SwiftData 

@Model
struct Artist: Codable {
    @Attribute var followers: [String]?
    @Attribute var userName: String?
    @Attribute var following: Int?

    init(followers: [String]? = nil, userName: String? = nil, 
    following: [String]? = nil ) {
        self.followers = followers
        self.userName = userName
        self.following = following
    }
}



Why SwiftData?

  • Model Flexibility - Models made using SwiftData are very flexible which can be adjusted with the changing data flow.
  • Security - It provides modern day security standards to protect data.
  • Easy to use - It simplifies data management tasks such as fetching, saving and deleting data.
  • Compatible with CoreData - It is built on the platform of the CoreData, Apple’s framework used for data persistence.
  • Error Handling - It provides better error handling as it helps catching errors in compile-time rather than at runtime.

Phase 3 - Dashboard views

Components of Dashboard page

Here are the components of dashboard on the website -

Note: The root URL of all the APIs being used is https://api.listenbrainz.org as mentioned in the documentation.

The tentative figma mockup can be found here.

1. Listens

Listens page is our first dashboard page which has following sections -

1.) Listen-count indicator -

Use the endpoint GET /1/user/(user_name)/listen-count to get the listens count of the logged in user.

2.) Followers and following -

Make layout for followers and following as mentioned in the tentative mockup for listens by using the following endpoints -

  • POST /1/user/(user_name)/follow - This endpoint let users to follow other users from the app.
  • POST /1/user/(user_name)/unfollow - This endpoints let users to unfollow other users.
  • GET /1/user/(user_name)/followers - return followers of the user.
  • GET /1/user/(user_name)/following - returns array of users that logged-in user is following.

3.) Recent Listens - This section is already in action.

  • GET /1/user/(user_name)/listens - Used this endpoint to get the recent listens of the user.

UI Mockup (tentative) -

2. Statistics

In the Statistics section, we have following components -

1.) Listening Activity -

  • GET /1/stats/user/(user_name)/listening-activity - This endpoint will be used representing the listening activity of a user in the form of bar chart.
  • Use parameter listen_count from the endpoint to represent the listening activity of the user in a particular time frame.
"listening_activity": [
            {
                "from_ts": 1009843200,
                "listen_count": 5,
                "time_range": "2002",
                "to_ts": 1041379199
            }

2.) Top artists -

  • GET /1/stats/user/(user_name)/artists - use this endpoint for the top artists of a given user_name.
  • Top artists will be implemented in the form of a list inside a ScrollView.

3.) Top tracks and Top albums -

  • GET /1/stats/user/(user_name)/recordings - For the top tracks of a given user_name.
  • GET /1/stats/user/(user_name)/releases - For the top albums of a given user_name.
  • Top albums and tracks will be implemented in a similar way to that of Top artists with minor UX changes.

4.) Daily activity -

  • GET /1/stats/user/(user_name)/daily-activity?range=year - For representing the daily activity of user in the form of heat map.
  • Heat map will be implemented by using LazyHGrid (customizable grid in SwiftUI) and listen_count will be added on the basis of hour as follows.
"daily_activity": {
            "Friday": [
                {
                    "hour": 0,
                    "listen_count": 12
                },
                {
                    "hour": 1,
                    "listen_count": 6
                }

5.) Artist Origins -

  • GET /1/stats/user/(user_name)/artist-map - For representing the Artists origin of the artists listened by user in a world map.
  • Fill the world map with the country parameter in the endpoint for the corresponding artist.
"artist_map": [
            {
                "country": "India",
                "artist_count": 34
            }

UI mockup (tentative) -

3.Taste

1.) Loved/Hated recordings -

  • GET /1/feedback/user/(user_name)/get-feedback - Use this endpoint to get the list of loved and hated recordings for a given username.
  • Make two seperate components for Loved and Hated recordings and implement it in the form of a list.

2.) Pinned Tracks -

  • GET /1/(user_name)/pins - for getting list of recordings pinned by user.
  • GET /1/(user_name)/pins/current - for getting the current pins of the user.

UI mockup (tentative) -

4. Playlists

In playlists section, the playlists created for user and in which user is a collaborator will be displayed. The endpoints used are -

  • POST /1/playlist/create - Use this endpoint for creating a playlist
  • GET /1/user/(playlist_user_name)/playlists - to fetch all the playlists created by user.
  • GET /1/user/(playlist_user_name)/playlists/createdfor - to fetch playlists which are created for user.
  • GET /1/user/(playlist_user_name)/playlists/collaborator - to fetch playlists in user is collaborator
  • Use playlist’s user name and mbid for accessing the playlists.

UI mockup (tentative) -

5. Created for you

In Created for you section, there are following components -
1.) Weekly Jams
2.) Weekly Explorations
3.) Last Week’s explorations
4.) Last Week’s jams
5.) Top Discoveries
6.) Top missed recordings

Use respective endpoints for these components and represent them in a horizontally scrollable card depicting the title and list of listens.

UI mockup (tentative) -


Phase 4 - User Exploration

Expected outcome of user exploration

To enable users not only to view their own dashboard within the app but also to explore the dashboards of other users and to make a more connected and interactive user experience.

In user exploration, users’ dashboard can be viewed using following ways -
1.) Search bar - Users can search other usernames in the search bar in the feed.
2.) Feed - Inside feed user exploration can be achieved by clicking on the usernames present.
3.) Followers/Following - from the list of followers and following in the dashboard

The process of User exploration includes -

1.) Navigation

  • In the view named DashboardView which contains all the views as mentioned above.
  • Establish navigation between all the views such that all of them are interconnected.

2.) Make usernames clickable

  • Use button such that username is clickable.
  • They will trigger on every action on username.

3.) Capture the username being tapped

  • Create a state variable , let’s say selectedUsername which is used to store the state when any username is clicked.
  • SwiftUI’s State property wrapper allows you to store and update state within a view. When a username is clicked, this state variable will hold the selected username.

4.) Pass the username to DashboardView

  • In this, updated username is parsed to the DashboardView.
  • After passing the new username, the dashboard of that respective user can be views.

5.) Modify view model for new username

Perform necessary changes in the view model according to the change in the state by clicking on the new username.

Example - In the FeedView, user exploration can be achieved as follows -

struct FeedView: View {
    @EnvironmentObject var viewModel: FeedViewModel
    @State private var selectedUsername: String?

    var body: some View {
        VStack() {
            Button(action: {
                // Capture the selected username
                selectedUsername = event.username
            }) {
                EventDescriptionView(event: event)
            }

            // Navigate to user dashboard when a username is selected
            NavigationLink(
                destination: DashboardView(username: selectedUsername ?? ""),
                isActive: $selectedUsername,
                label: { EmptyView() }
            )
            .hidden()
        }
    }
}


Timeline

Pre-Community Bonding Period (April 2 - May 1):

The UI/UX of the entire app needs to be made consistent to that mentioned in the figma, need to revamp some native components with the new design.

Community Bonding Period (May 1 - May 26):

The tentative mockup for dashboard to be discussed with the design lead and mentor to incorporate all the changes and requirements.

Coding Period

Phase 1 - User Search and feed revamp

Week 1 (May 27 - Jun 3)

  • Implement search users feature.
  • Add search button in the top bar.
  • Make a interactive list of users on searching in the textfield
  • Write unit tests for search users and validate the results for it.

Week 2 (Jun 3 - Jun 10)

  • Revamp the feed including the listen card and add other functionalities.
  • Add support for CritiqueBrainz review
  • Create a dialogue allowing user to open in MusicBrainz ,pin, recommend, personally recommend and write a review.
  • Adding support for hiding, unhiding and deleting an event for which following endpoints will be used.
    * POST /1/user/(user_name)/feed/events/delete
    * POST /1/user/(user_name)/feed/events/hide
    * POST /1/user/(user_name)/feed/events/unhide
  • Implement thorough testing for CritiqueBrainz review feature and write tests for pin and other features also.

Phase 2 - Dashboard Setup

Week 3-4 (Jun 10 - Jun 24)

  • Set repository for dashboard.
  • RepositoryImpl for dashboard in which all the networking requests will be taken care of.
  • Perform all the networking requests on a server.
  • Make models for dashboard using SwiftData after running all the api requests.
  • Make sure that the models contain all the parameters which are required in the frontend.
  • Create a view model that conforms to repository for creating functions that would be necessary to perform necessary changes from api to the UI.
  • Write integration tests ensuring the efficient working of networking requests.

Phase 3 - Dashboard views

Week 5 (Jun 24 - Jul 1)

  • Revamp listens component in the dashboard.
  • Add total listens feature and followers/following displayer.
  • Create a main view for dashboard for including all the other views in it.

Week 6 (Jul 1 - Jul 8)

  • Implement Statistics screen
  • In statistics listening activity, top artists, top tracks, top albums, daily activity and artists origin will be implemented.

Week 7 (Jul 8 - Jul 15)

  • In this week, taste and playlists section will be implemented.
  • Please go through the Plan Of Action above to get the exact implementation of Taste and Playlists.
  • Prepare midterm evaluation before the proposed deadline.

Week 8 (Jul 15 - Jul 22)

  • Implement Created for you section with all the components mentioned.
  • Write Unit tests for the components made and implement detailed testing ensuring proper execution of the functionality.
  • Do a detailed design analysis of components made with the design lead.

Week 9 (Jul 22 - Jul 29)

  • Perform design enhancements (if any)
  • Carry out comprehensive testing on all iOS devices including iPads.

Phase 4 - User Exploration

Week 10 (Jul 29 - Aug 5)

  • Implement logic for user exploration.
  • Create states when the username is clicked.
  • Username can be tapped from feed, dashboard or from search users, take account all the possibilities.
  • Write integration tests for user exploration logic and navigation, different navigation paths and edge cases.

Week 11 (Aug 5 - Aug 12)

  • Perform necessary changes in view model for user exploration.
  • Setup navigation links for dashboard view, which changes with respect to username.
  • Do thorough testing of the dashboard exploration.

Week 12 (Aug 12 - Aug 19)

  • Look out for all the edge cases in user exploration.
  • Pending work, if any

Buffer Week (Aug 19 - Aug 26)

  • Have thorough discussion with the mentor regarding the implementation.
  • Lookout for anything that is left and perform necessary actions for completing it.
  • Conduct overall performance testing of features incorporated.

Stretch Goals

  • Review Player section of the app and add other features with having approval from the mentor.
  • Add more features in the Explore section such as fresh releases and cover art collage.

Community affinities

What type of music do you listen to?
I am really fond of Punjabi music and Alternative Indie. My favourite artists and their mbids are -
1.) Amrinder Gill - cd74f170-639f-4ff9-b01f-29b8e82912ae
2.) Coldplay - cc197bad-dc9c-440d-a5b5-d52ba2e14234
3.) Vansire - 0a7920d5-135b-4bca-885c-ebd79f0d5d9f

What aspects of MusicBrainz/ListenBrainz/BookBrainz/Picard interest you the most?
Having contributed and being a music geek, I love ListenBrainz and MusicBrainz the most. As an active user of Listenbrainz website and app for a year, I love a lot of things, YIM is my personally favourite because it comprehensively tells me about my listening activity.

Have you ever used any of our projects in the past?
I have been an active user of Listenbrainz, MusicBrainz and BookBrainz. I have used bookbrainz also to get works of my favourite authors at one place.

Programming precedents

When did you first start programming?
I started my programming journey in my first year of college back in 2021, I picked up C++ learned some basics and then started Swift few months after. I made some apps on the iOS side alongside learning.

I have been an active user for Listenbrainz-android for more than a year and I found that app very fascinating. From being a user to contributor, I have gone through a learning odyssey in the process of contributing in LB-iOS.

Have you contributed to other open source projects? Do you have other code we can look at?What sorts of programming projects have you done on your own time?
No, Listenbrainz-iOS is my first open source project, I started contributing in April of 2023 and it’s been a tremendous learning curve for me since then. I have been learning from each member of the community.

I have made Animate yourself, an iOS app for cartoonizing the images of the user. in this app I have used pre-trained models for conversion and I have also implemented caching in it.

Stress Buster - developed this project, incorporating the use of various frameworks in SwiftUI including PencilKit, AVFoundation and various user friendly animations.

Practical requirements

What computer(s) do you have available for working on your SoC project?
I have Macbook Air M1 with 8 gigs of RAM which runs MacOS Sonoma 14.2.1. I use the Xcode IDE for contributing to Listenbrainz-iOS.

How much time do you have available per week, and how would you plan to use it?
Since I’ll be having my summer break from Uni at that time, I plan to provide ~35 to 40 hours/week for my SoC project.

References

ListenBrainz documentation — ListenBrainz 0.1.0 documentation

GitHub - Alamofire/Alamofire: Elegant HTTP Networking in Swift

Combine | Apple Developer Documentation

SwiftData - Xcode - Apple Developer

Google Summer of Code 2024 Timeline  |  Google for Developers

3 Likes

Thanks a lot for your proposal, @theflash! :100:
I have read your proposal and it looks quite good. Kudos!

I would like to address a few things and have some questions for you.

  1. Why does the pin a recording endpoint not require a user token? That shouldn’t be the case according to me. Recordings — ListenBrainz 0.1.0 documentation
  2. Why don’t we use SwiftData for the upcoming state management? SwiftData - Xcode - Apple Developer This could act as a direct replacement for creating complex viewmodels. If you seem a bit confident about this, I think we should incorporate them into the codebase.
  3. Please ensure that you only use Figma mockups handed over by @aerozol to match the designs in the app. I think the dashboard page might have a few tweaks here and there compared to the website in terms of swipeable tabs, etc. but we will let our designer finalize that.
  4. Found a couple of grammatical mistakes here and there. Best to re-read the proposal once and fix those.
  5. I think your project does more than just the Dashboard since in the first two weeks, you will be fixing the Feed and adding search as well. Best to rename the project name to something more comprehensive. I am fine with a new name. We can edit it on the ideas page also then.
  6. You have only mentioned adding tests once in the project. I think we should include them at every stage of the project and complete the respective tests as we move along.

Great work otherwise, looking forward to these revisions!

2 Likes

Thanks a lot @akshaaatt for your feedback!, After going through all the suggestions, i have updated the proposal, please have a look.

True!, I have fixed that.

Indeed, that’s a really good way of implementing data management and persistence within the dashboard because of the flexibility it provides, explored it and will be using it in the project.

These are just tentative mockups to get a blueprint of how dashboard will look, I am looking forward to @aerozol to clinch the design for dashboard and provide the finalised design.

Fixed a lot of them, sorry for that.

I have devised a new name Dashboard Page and Feed revamp in Listenbrainz iOS app for all users.

I have added them at each stage required.

2 Likes

LGTM @theflash. I do not have any more feedback. Kudos!

1 Like

Thanks for your valuable review!

1 Like