<commit_before>import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

import '../marvel.dart';
import '../widgets/loading_image.dart';
import '../widgets/marvel_logo.dart';
import '../widgets/search_bar.dart';

part 'home.freezed.dart';

const kCharactersPageLimit = 50;

@freezed
abstract class CharacterPagination with _$CharacterPagination {
  factory CharacterPagination({
    @required int page,
    String name,
  }) = _CharacterPagination;
}

// workaround to https://github.com/dart-lang/sdk/issues/41449
final $family = FutureProvider.autoDispose.family;
final characterPages =
    $family<MarvelListCharactersReponse, CharacterPagination>(
  (ref, meta) async {
    // Cancel the page request if the UI no-longer needs it before the request
    // is finished.
    // This typically happen if the user scrolls very fast
    final cancelToken = CancelToken();
    ref.onDispose(cancelToken.cancel);

    final repository = ref.read(repositoryProvider);
    final charactersResponse = await repository.fetchCharacters(
      offset: meta.page * kCharactersPageLimit,
      limit: kCharactersPageLimit,
      nameStartsWith: meta.name,
      cancelToken: cancelToken,
    );

    // Once a page was downloaded, preserve its state to avoid re-downloading it again.
    ref.maintainState = true;
    return charactersResponse;
  },
);

final charactersCount = Provider.family<AsyncValue<int>, String>((ref, name) {
  final meta = CharacterPagination(page: 0, name: name);

  return ref.watch(characterPages(meta)).whenData((value) => value.totalCount);
});

@freezed
abstract class CharacterOffset with _$CharacterOffset {
  factory CharacterOffset({
    @required int offset,
    @Default('') String name,
  }) = _CharacterOffset;
}

final characterAtIndex =
    Provider.family<AsyncValue<Character>, CharacterOffset>((ref, query) {
  final offsetInPage = query.offset % kCharactersPageLimit;

  final meta = CharacterPagination(
    page: query.offset ~/ kCharactersPageLimit,
    name: query.name,
  );

  return ref.watch(characterPages(meta)).whenData(
        (value) => value.characters[offsetInPage],
      );
});

class Home extends HookWidget {
  const Home({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return useProvider(charactersCount('')).when(
      loading: () => Container(
        color: Colors.white,
        child: const Center(child: CircularProgressIndicator()),
      ),
      error: (err, stack) {
        return Scaffold(
          appBar: AppBar(title: const Text('Error')),
          body: Center(
            child: Text('$err'),
          ),
        );
      },<commit_msg>update marvel example as a follow-up to ref.watch changes<commit_after>import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

import '../marvel.dart';
import '../widgets/loading_image.dart';
import '../widgets/marvel_logo.dart';
import '../widgets/search_bar.dart';

part 'home.freezed.dart';

const kCharactersPageLimit = 50;

@freezed
abstract class CharacterPagination with _$CharacterPagination {
  factory CharacterPagination({
    @required int page,
    String name,
  }) = _CharacterPagination;
}

// workaround to https://github.com/dart-lang/sdk/issues/41449
final $family = FutureProvider.autoDispose.family;
final characterPages =
    $family<MarvelListCharactersReponse, CharacterPagination>(
  (ref, meta) async {
    // Cancel the page request if the UI no-longer needs it before the request
    // is finished.
    // This typically happen if the user scrolls very fast
    final cancelToken = CancelToken();
    ref.onDispose(cancelToken.cancel);

    final repository = ref.read(repositoryProvider);
    final charactersResponse = await repository.fetchCharacters(
      offset: meta.page * kCharactersPageLimit,
      limit: kCharactersPageLimit,
      nameStartsWith: meta.name,
      cancelToken: cancelToken,
    );

    // Once a page was downloaded, preserve its state to avoid re-downloading it again.
    ref.maintainState = true;
    return charactersResponse;
  },
);

final charactersCount =
    Provider.autoDispose.family<AsyncValue<int>, String>((ref, name) {
  final meta = CharacterPagination(page: 0, name: name);

  return ref.watch(characterPages(meta)).whenData((value) => value.totalCount);
});

@freezed
abstract class CharacterOffset with _$CharacterOffset {
  factory CharacterOffset({
    @required int offset,
    @Default('') String name,
  }) = _CharacterOffset;
}

final characterAtIndex = Provider.autoDispose
    .family<AsyncValue<Character>, CharacterOffset>((ref, query) {
  final offsetInPage = query.offset % kCharactersPageLimit;

  final meta = CharacterPagination(
    page: query.offset ~/ kCharactersPageLimit,
    name: query.name,
  );

  return ref.watch(characterPages(meta)).whenData(
        (value) => value.characters[offsetInPage],
      );
});

class Home extends HookWidget {
  const Home({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return useProvider(charactersCount('')).when(
      loading: () => Container(
        color: Colors.white,
        child: const Center(child: CircularProgressIndicator()),
      ),
      error: (err, stack) {
        return Scaffold(
          appBar: AppBar(title: const Text('Error')),
          body: Center(
            child: Text('$err'),
          ),
        );
      },
{'fraction_non_alphanumeric': 0.11720226843100189, 'fraction_numerical': 0.002749613335624678, 'mean_word_length': 3.88255033557047, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 19, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5312746', 'n_tokens_mistral': 1723, 'n_tokens_neox': 1706, 'n_words': 407}