0

I have a streaming app consists of multiple channels and each channel has DVRs.On the main page, all channels are displayed in rows according to their categories. And When the user clicks on a channel item it goes to a detailed page that contains DVRs in a horizontally scrollable row. All channels and DVR items have images and I am loading images from URL by using URLImage (https://github.com/dmytro-anokhin/url-image) library. The issue is when I run the app, the channel images load from right bottom to top left which is from the last item to the first item. When I click on a channel and navigate to a detailed screen, the images for the DVRs start loading from right to left, which is from the last item to the first item. And this creates a problem because the channels have too many DVR data and it takes 5 seconds to load all images. It would be great if it started to load the images from the first item so even if it takes 5 seconds the user would not realize and get effected.

I do not understand why it acts this way. Is there a solution to fix this issue? How can I force it to start loading from the first item to the last one. Here is my code to display DVRs in:

    ForEach(1..<chan.getDVR().count, id: \.self){index in

       Button(action:
       {
           self.str = self.chan.getDVR()[index].getHlsStreamURL()
           self.refresh = false
           self.ind = index

       }) {
            dvrItem(DVRItem: self.chan.getDVR()[index])
                .buttonStyle(PlainButtonStyle())
                .padding(.trailing,3)
                .cornerRadius(7)

       }.buttonStyle(PlainButtonStyle())             
    }

and the dvrItem:

struct dvrItem: View {

        var DVRItem: dvr

        var body: some View {
             VStack( alignment: .leading) {
                URLImage(URL(string: DVRItem.getLogoUrlHD().replacingOccurrences(of: "http", with: "https", options: .literal, range: nil))!,  placeholder: { _ in Image("nologo").resizable().aspectRatio(contentMode: .fill).clipped() } ){
                    proxy in
                    proxy.image
                        .resizable()                     // Make image resizable
                        .aspectRatio(contentMode: .fill) // Fill the frame
                        .clipped()                       // Clip overlaping parts
                }
                .frame(width: 198, height: 114)
                .cornerRadius(7)
                .padding(.leading, 10)
                .padding(.top, 5)
                Text(self.DVRItem.getName())
                    .foregroundColor(Color.white)
                    .padding(.leading, 5)
                    .padding(.trailing, 5)

                Text(self.DVRItem.getDescription())
                    .foregroundColor(Color(red: 80.0/150, green: 80.0/150, blue: 80.0/150))
                    .lineLimit(nil)
                    .padding(.leading, 5)
                    .padding(.trailing, 5)
                Spacer()
                    .frame(height: 5)

            }
        }
    }

    struct dvrItem_Previews: PreviewProvider {
        static var previews: some View {
            dvrItem(DVRItem: channels[0].getDVR()[0])
        }
    }

What am I going wrong? By the way I tried to load only the first 10 DVR items like ForEach(1..<10, id: \.self){index in but it gave run time error.

Asperi
  • 228,894
  • 20
  • 464
  • 690
C.Aglar
  • 1,290
  • 2
  • 14
  • 30

1 Answers1

0

After trying many things I resolved the issue by using URLImage Library's option.

URLImages has a delay option that you can use to delay the process of image loading. And usage is as follows:

    URLImage(URL(string: DVRItem.getLogoUrlHD().replacingOccurrences(of: "http", with: "https", options: .literal, range: nil))!, delay: 0.25,  placeholder: { _ in Image("nologo").resizable().aspectRatio(contentMode: .fill).clipped() } ){
        proxy in
        proxy.image
            .resizable()                     // Make image resizable
            .aspectRatio(contentMode: .fill) // Fill the frame
            .clipped()                       // Clip overlaping parts
    }

I updated my DVRItem and added a new variable called index:

    var ind: Int

And used that variable to load the first 5 elements without delay, load the next 15 elements with 0.15 delay and load the rest of the elements with 0.25 delay. That way it immediately loads the first 5 elements and then loads the rest. My final code is like this:

struct dvrItem: View {

    var DVRItem: dvr
    var ind: Int

    var body: some View {
         VStack( alignment: .leading) {
            URLImage(URL(string: DVRItem.getLogoUrlHD().replacingOccurrences(of: "http", with: "https", options: .literal, range: nil))!, delay: (self.ind < 5) ? 0 : (self.ind < 20 ? 0.15 : 0.25),  placeholder: { _ in Image("nologo").resizable().aspectRatio(contentMode: .fill).clipped() } ){
                proxy in
                proxy.image
                    .resizable()                     // Make image resizable
                    .aspectRatio(contentMode: .fill) // Fill the frame
                    .clipped()                       // Clip overlaping parts
            }
            .frame(width: 198, height: 114)
            .cornerRadius(7)
            .padding(.leading, 10)
            .padding(.top, 5)
            Text(self.DVRItem.getName())
                .foregroundColor(Color.white)
                .padding(.leading, 5)
                .padding(.trailing, 5)

            Text(self.DVRItem.getDescription())
                .foregroundColor(Color(red: 80.0/150, green: 80.0/150, blue: 80.0/150))
                .lineLimit(nil)
                .padding(.leading, 5)
                .padding(.trailing, 5)
            Spacer()
                .frame(height: 5)

        }
    }
}

struct dvrItem_Previews: PreviewProvider {
    static var previews: some View {
        dvrItem(DVRItem: channels[0].getDVR()[0], ind: 0)
    }
}

And I call the DVRItem as follows and assign the ind with index values:

ForEach(1..<chan.getDVR().count, id: \.self){index in

   Button(action:
   {
       self.str = self.chan.getDVR()[index].getHlsStreamURL()
       self.refresh = false
       self.ind = index

   }) {
        dvrItem(DVRItem: self.chan.getDVR()[index], ind: index)
            .buttonStyle(PlainButtonStyle())
            .padding(.trailing,3)
            .cornerRadius(7)

   }.buttonStyle(PlainButtonStyle())             
}

I still don't know why it starts loading from the last item but this solved my problems. I tried similar solutions like in this post In SwiftUI, where are the control events, i.e. scrollViewDidScroll to detect the bottom of list data but they don't work for horizontal scrolls.

C.Aglar
  • 1,290
  • 2
  • 14
  • 30