PlayListNotifier

mail@pastecode.io avatar
unknown
dart
2 years ago
8.7 kB
1
Indexable
Never
import 'dart:async';
import 'dart:developer';
import 'package:audioplayers/audioplayers.dart';
import 'package:base_architecture/data_layer/api/api_provider.dart';
import 'package:base_architecture/data_layer/models/api_models/Dto/add_to_library_dto.dart';
import 'package:base_architecture/presentation/notifiers/book_view_notifier.dart';
import 'package:base_architecture/presentation/pages/main/main_page.dart';
import 'package:card_swiper/card_swiper.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:volume_controller/volume_controller.dart';

class PlayListNotifier extends ChangeNotifier {
  int? _listIndex = 0;
  changeIndex(int index) {
    _listIndex = index;
    notifyListeners();
  }

  bool isLiked = false;
  void changeIsLiked() {
    isLiked = !isLiked;
    notifyListeners();
  }

  bool _isDrive = false;
  void setIsDrive() {
    _isDrive = !isDrive;
    notifyListeners();
  }

  final SwiperController _swiperController = SwiperController();
  // Player related
  final AudioPlayer _player = AudioPlayer();
  AudioPlayer get player => _player;
  bool _isPlaying = false;
  Duration _reach50 = Duration();
  Duration _reach85 = Duration();
  bool _didSetSource = false;
  bool _setNewSource = false;
  Duration _currentPosition = const Duration(
    seconds: 0,
    minutes: 0,
  );
  Duration _duration = const Duration(
    seconds: 0,
    minutes: 0,
  );
  VolumeController _volumeController = VolumeController();
  double _volumeListenerValue = 0;
  double _getVolume = 0;
  double _setVolumeValue = 0;
  double _playRate = 1.0;

  // Player Getters
  bool get isPlaying => _isPlaying;
  Duration? get reach50 => _reach50;
  bool get didSetSource => _didSetSource;
  Duration get position => _currentPosition;
  Duration get duration => _duration;
  VolumeController get volumeController => _volumeController;
  double get playRate => _playRate;
  int? get listIndex => _listIndex;

  Future<void> play(String url) async {
    if (!didSetSource) {
      await setSource(
        url,
      );
    }
    if (isPlaying) {
      _player.pause();
      _isPlaying = false;
    } else {
      _player.resume();
      _isPlaying = true;
    }

    checkPlayTime();
    notifyListeners();
  }

  Future<void> setSource(String source) async {
    await _player.setSourceUrl(
      source,
    );
    volumeController.listener((double volume) {
      _volumeListenerValue = volume;
      _player.setVolume(_volumeListenerValue);
      notifyListeners();
    });

    // await _player.play(UrlSource(source));

    Timer.periodic(const Duration(seconds: 1), (Timer timer) async {
      await _player.getCurrentPosition().then(
        (Duration? value) {
          _currentPosition = value!;
          notifyListeners();
        },
      );
      await _player.getDuration().then(
        (Duration? value) {
          _duration = value!;
          notifyListeners();
        },
      );
      if (_currentPosition == duration) {
        _isPlaying = false;
        notifyListeners();
      }
    });
    _player.onPlayerComplete.listen((complete) {
      _isPlaying = false;

      notifyListeners();
    });

    _didSetSource = true;
    notifyListeners();
  }

  void handleSeek(double seconds) {
    _currentPosition = Duration(seconds: seconds.floor().toInt());
    _player.seek(_currentPosition);
    notifyListeners();
  }

  void pause() {
    _player.pause();
    _isPlaying = false;
    notifyListeners();
  }

  void resume() {
    _player.resume();
    _isPlaying = true;
    notifyListeners();
  }

  void getComplete() {
    _currentPosition = _duration;
    _isPlaying = false;
    notifyListeners();
  }

  void disposePlayer() {
    _player.dispose();
    _isPlaying = false;
  }

  double? playTime50;
  bool didLog50 = false;
  double? playTime85;
  bool didLog85 = false;
  void checkPlayTime() async {
    BookViewNotifier bookViewNotifier = Provider.of<BookViewNotifier>(
      navigatorKey.currentContext!,
      listen: false,
    );
    await Future.delayed(Duration(seconds: 2));
    playTime50 = (_duration.inSeconds ~/ 2).toDouble();
    playTime85 = (_duration.inSeconds * 0.85).toDouble();
    if (!bookViewNotifier
            .bookDetails.data!.first.soundFiles![listIndex!].isFifty! &&
        !bookViewNotifier
            .bookDetails.data!.first.soundFiles![listIndex!].isEightyFive!) {}
    streamDelayer(_player.onPositionChanged, const Duration(seconds: 1))
        .listen((Duration event) async {
      log('Current::::: ${_currentPosition.inSeconds} 50% equals $playTime50');
      if (_currentPosition.inSeconds >= playTime50! &&
          !bookViewNotifier
              .bookDetails.data!.first.soundFiles![listIndex!].isFifty!) {
        bookViewNotifier
            .bookDetails.data!.first.soundFiles![listIndex!].isFifty = true;
        print('reached 50%');
        setPlayTime50();
      } else if (_currentPosition.inSeconds >= playTime85! &&
          !bookViewNotifier
              .bookDetails.data!.first.soundFiles![listIndex!].isEightyFive!) {
        bookViewNotifier.bookDetails.data!.first.soundFiles![listIndex!]
            .isEightyFive = true;
        print('reached 85%');
        setPlayTime85();
      }
    });
  }

  setPlayTime50() {
    // _reach50 = pt;
    // print(_reach50);
    BookViewNotifier bookViewNotifier = Provider.of<BookViewNotifier>(
      navigatorKey.currentContext!,
      listen: false,
    );
    AddToLibraryDto log50 = AddToLibraryDto(
      related_id: bookViewNotifier.bookDetails.data!.first.id.toString(),
      chapter_id: bookViewNotifier
          .bookDetails.data!.first.soundFiles![listIndex!].id
          .toString(),
      type: 1,
      percentage: 50,
    );

    log(log50.toJson().toString());
    addToLibrary(log50);
    notifyListeners();
  }

  setPlayTime85() {
    // _reach85 = pt;
    // print(_reach85);
    BookViewNotifier bookViewNotifier = Provider.of<BookViewNotifier>(
      navigatorKey.currentContext!,
      listen: false,
    );
    AddToLibraryDto log85 = AddToLibraryDto(
      related_id: bookViewNotifier.bookDetails.data!.first.id.toString(),
      chapter_id: bookViewNotifier
          .bookDetails.data!.first.soundFiles![listIndex!].id
          .toString(),
      type: 1,
      percentage: 85,
    );
    log(log85.toJson().toString());
    addToLibrary(log85);
    notifyListeners();
  }

  void seek(Duration duration) {
    _player.seek(_currentPosition + duration);
    bool backward = duration.isNegative;
    Duration newDuration = _currentPosition + duration;
    if (backward) {
      bool lessThanMinimum = _currentPosition.inSeconds < 15;
      Duration zero = Duration.zero;

      /// Commented By: Hasan Armoush
      /// Below we do three steps and it should remain in the same order
      /// We set the value of [_currentPosition] to a value [zero, newDuration]
      /// Immediately after setting the value we call the [notifyListener]
      /// In order to reflect state quickly on the UI
      /// Since [_player.seek is a future] and we should wait for it
      if (lessThanMinimum) {
        _currentPosition = zero;
        notifyListeners();
        _player.seek(zero);
      } else {
        _currentPosition = newDuration;
        notifyListeners();

        _player.seek(newDuration);
      }
    } else {
      _currentPosition = newDuration;
      notifyListeners();
      _player.seek(newDuration);
    }
  }

  void setPlayRate(double rate) async {
    await _player.setPlaybackRate(rate);
    if (!isPlaying) {
      await _player.pause();
    }
    _playRate = rate;
    notifyListeners();
  }

  final List<double> _playerSpeeds = [
    0.50,
    0.75,
    1.0,
    1.5,
    1.75,
    2.0,
  ];

  final List<String> _playerTimers = [
    '15',
    '30',
    '45',
    'نهاية الفصل',
  ];

  double _playerSpeed = 1.0;
  String _selectedTimer = '';
  double get playerSpeed => _playerSpeed;
  String get selectedTimer => _selectedTimer;
  List<double> get playerSpeeds => _playerSpeeds;
  List<String> get playerTimers => _playerTimers;
  SwiperController get swiperController => _swiperController;
  bool get isDrive => _isDrive;

  setPlayerSpeed(double value) {
    _playerSpeed = value;
    notifyListeners();
  }

  setPlayerTimer(String value) {
    _selectedTimer = value;
    notifyListeners();
  }

  addToLibrary(AddToLibraryDto param) async {
    await ApiProvider(httpClient: Dio()).postAudioToLibrary(param);
  }
}

extension Player on PlayListNotifier {}

Stream<T> streamDelayer<T>(Stream<T> inputStream, Duration delay) async* {
  await for (final val in inputStream) {
    yield val;
    await Future.delayed(delay);
  }
}