pauli2406 / xtream_code_client

MIT License
3 stars 3 forks source link

Error: 'Null' is not a subtype of type 'List<dynamic>' when fetching category items #12

Open fvdf opened 2 months ago

fvdf commented 2 months ago

Hello,

I am using the xtream_code_client library to develop an IPTV app with Flutter. I've encountered a runtime issue when trying to display items within a category. The error occurs as: "Error type 'Null' is not a subtype of type 'List' in type cast."

Steps to reproduce:

  1. Initialize the XtreamCode client with valid credentials.
  2. Navigate to any category (live, vod, or series).
  3. Fetch items for the selected category.

Expected behavior: The items within the selected category should be fetched and displayed without errors.

Actual behavior: Receiving a type cast error indicating a null value where a list was expected.

Code snippet:

Future<List<dynamic>> fetchItems() {
  switch (type) {
    case 'live':
      return client.livestreamItems(category: category);
    case 'vod':
      return client.vodItems(category: category);
    case 'series':
      return client.seriesItems(category: category);
    default:
      throw Exception('Unknown item type');
  }
}

Additional Context

The error might be due to how null responses are handled when no items are found, or possibly an issue with the data format returned by the server.

Could you please help resolve this issue or provide guidance on how to handle such cases?

Thank you!

fvdf commented 2 months ago

Here is my code to reproduce the error, and I would like to add that I have tried with several service providers. The result is similar with only one allowing access to the live list.

import 'package:flutter/material.dart';
import 'package:xtream_code_client/xtream_code_client.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await initializeXtreamCode();
  runApp(const MyApp());
}

Future<void> initializeXtreamCode() async {
  await XtreamCode.initialize(
    url: 'http://XX.org',
    port: '8080',
    username: 'XX',
    password: 'XX',
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) => MaterialApp(
        title: 'Xtream IPTV',
        theme: ThemeData.from(
            colorScheme: const ColorScheme.light(primary: Colors.blue)),
        home: const HomeScreen(),
      );
}

class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(title: const Text('Xtream IPTV')),
        body: Column(
          children: ['live', 'vod', 'series']
              .map((type) => ListTile(
                    title: Text('$type Categories'),
                    onTap: () => Navigator.push(
                        context,
                        MaterialPageRoute(
                            builder: (_) => CategoryScreen(
                                type: type,
                                client: XtreamCode.instance.client))),
                  ))
              .toList(),
        ),
      );
}

class CategoryScreen extends StatelessWidget {
  final String type;
  final XtreamCodeClient client;

  const CategoryScreen({super.key, required this.type, required this.client});

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(title: Text('$type Categories')),
        body: FutureBuilder<List<dynamic>>(
          future: fetchCategories(),
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.done &&
                snapshot.hasData) {
              return ListView.builder(
                itemCount: snapshot.data!.length,
                itemBuilder: (_, index) => ListTile(
                  title: Text(snapshot.data![index].categoryName.toString()),
                  onTap: () => Navigator.push(
                      context,
                      MaterialPageRoute(
                          builder: (_) => ItemsScreen(
                              type: type,
                              category: snapshot.data![index],
                              client: client))),
                ),
              );
            }
            return snapshot.hasError
                ? Text('Error: ${snapshot.error}')
                : const CircularProgressIndicator();
          },
        ),
      );

  Future<List<dynamic>> fetchCategories() {
    switch (type) {
      case 'live':
        return client.liveStreamCategories();
      case 'vod':
        return client.vodCategories();
      case 'series':
        return client.seriesCategories();
      default:
        throw Exception('Unknown category type');
    }
  }
}

class ItemsScreen extends StatelessWidget {
  final String type;
  final dynamic category;
  final XtreamCodeClient client;

  const ItemsScreen(
      {super.key,
      required this.type,
      required this.category,
      required this.client});

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(title: Text('$type Items')),
        body: FutureBuilder<List<dynamic>>(
          future: fetchItems(),
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.done &&
                snapshot.hasData) {
              return ListView.builder(
                itemCount: snapshot.data!.length,
                itemBuilder: (_, index) => ListTile(
                  title: Text(snapshot.data![index].name),
                  onTap: () {},
                ),
              );
            }
            return snapshot.hasError
                ? Text('Error: ${snapshot.error}')
                : const CircularProgressIndicator();
          },
        ),
      );

  Future<List<dynamic>> fetchItems() {
    switch (type) {
      case 'live':
        return client.livestreamItems(category: category);
      case 'vod':
        return client.vodItems(category: category);
      case 'series':
        return client.seriesItems(category: category);
      default:
        throw Exception('Unknown item type');
    }
  }
}
pauli2406 commented 2 months ago

This sounds like some provider do not provide some lists.. Will have to check that.