AsyncNotifier

샤워실의 바보·2024년 2월 16일
0
post-thumbnail

이 코드는 Flutter에서 Riverpod를 사용하여 비디오 타임라인과 비디오 업로드 기능을 구현하는 방법을 보여줍니다. AsyncNotifier를 활용해 비동기적으로 비디오 목록을 관리하고, ConsumerStatefulWidget을 사용해 상태 변화에 따라 UI를 업데이트합니다.

주요 구성 요소:

  • VideoModel: 비디오의 데이터 모델입니다. 여기서는 간단하게 제목만 포함하고 있습니다.
  • TimelineViewModel: 비디오 타임라인의 뷰 모델로, AsyncNotifier를 상속받아 비동기 로직을 처리합니다. 비디오 업로드를 시뮬레이션하는 uploadVideo 메서드를 포함하고 있습니다.
  • timelineProvider: TimelineViewModel의 인스턴스를 제공하는 프로바이더입니다.

VideoPreviewScreen (비디오 미리보기 화면):

  • ConsumerStatefulWidget을 사용해 Riverpod의 상태 관리 기능을 활용합니다. 사용자가 비디오를 업로드하려 할 때 timelineProvideruploadVideo 메서드를 호출합니다.

VideoTimelineScreen (비디오 타임라인 화면):

  • ConsumerStatefulWidget을 사용하며, timelineProvider에서 제공하는 상태에 따라 다른 UI를 표시합니다. 상태가 로딩 중일 때는 로딩 인디케이터를, 에러가 발생했을 때는 에러 메시지를, 데이터가 준비되었을 때는 RefreshIndicator와 함께 PageView.builder를 사용해 비디오 목록을 표시합니다.

주석 처리된 한국어 설명:

class VideoModel {
  String title;
  VideoModel({required this.title});
}

class TimelineViewModel extends AsyncNotifier<List<VideoModel>> {
  List<VideoModel> _list = [];

  Future<void> uploadVideo() async {
    state = const AsyncValue.loading(); // 비디오 업로드 시작 시 로딩 상태로 설정
    await Future.delayed(const Duration(seconds: 2)); // 비디오 업로드를 시뮬레이션하는 지연
    final newVideo = VideoModel(title: "${DateTime.now()}"); // 새 비디오 생성
    _list = [..._list, newVideo]; // 비디오 목록에 새 비디오 추가
    state = AsyncValue.data(_list); // 상태를 업데이트하여 UI에 반영
  }
}

class VideoPreviewScreen extends ConsumerStatefulWidget {
  final XFile video;
  final bool isPicked;

  const VideoPreviewScreen({super.key, required this.video, this.isPicked = false});

  
  VideoPreviewScreenState createState() => VideoPreviewScreenState();
}

class VideoPreviewScreenState extends ConsumerState<VideoPreviewScreen> {
  late final VideoPlayerController _videoPlayerController;
  bool _savedVideo = false;

  
  void initState() {
    super.initState();
    _initializeVideoPlayer(); // 비디오 플레이어 초기화
  }

  void _onUploadPressed() async {
    ref.read(timelineProvider.notifier).uploadVideo(); // 업로드 버튼 클릭 시 비디오 업로드 메서드 호출
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('설정'),
        actions: [
          IconButton(
            onPressed: ref.watch(timelineProvider).isLoading
                ? null // 로딩 중인 경우 업로드 버튼 비활성화
                : _onUploadPressed, // 로딩이 아닌 경우 업로드 메서드 호출
            icon: ref.watch(timelineProvider).isLoading
                ? const CircularProgressIndicator() // 로딩 중인 경우 로딩 인디케이터 표시
                : const FaIcon(FontAwesomeIcons.cloudArrowUp), // 로딩이 아닌 경우 업로드 아이콘 표시
          )
        ],
      ),
      body: // UI 구성 생략
    );
  }
}

이 코드는 비디오 앱의 기본적인 기능을 구현하는 데 필요한 Riverpod 사용법을 보여줍니다. AsyncNotifierConsumerStatefulWidget을 사용하여 비동기 작업의 상태 관리와 UI 반영을 보다 간결하고 효율적으로 처리할 수 있습니다.

아래는 VideoTimelineScreenbuild 메서드에서 ref.watch(timelineProvider).when(...)을 사용하여 비디오 타임라인을 동적으로 렌더링하는 방법에 대한 코드 예시와 함께 한국어로 된 주석을 포함한 설명입니다.

// VideoTimelineScreen의 build 메서드 내부

Widget build(BuildContext context) {
  // timelineProvider를 구독하고 현재 상태에 따라 조건부로 다른 위젯을 렌더링합니다.
  return ref.watch(timelineProvider).when(
    // 로딩 중 상태: CircularProgressIndicator를 중앙에 표시합니다.
    loading: () => const Center(
      child: CircularProgressIndicator(),
    ),
    // 에러 상태: 에러 메시지를 표시합니다.
    error: (error, stackTrace) => Center(
      child: Text(
        '비디오를 불러올 수 없습니다: $error',
        style: const TextStyle(color: Colors.white),
      ),
    ),
    // 데이터 로딩 완료 상태: RefreshIndicator와 PageView.builder를 사용하여 비디오 목록을 표시합니다.
    data: (videos) => RefreshIndicator(
      onRefresh: _onRefresh, // 화면을 아래로 당겨서 새로고침할 때 호출될 메서드
      displacement: 50, // 새로고침 인디케이터의 위치 조정
      edgeOffset: 20, // 새로고침 인디케이터와 화면 상단 간의 간격
      color: Theme.of(context).primaryColor, // 인디케이터의 색상
      child: PageView.builder(
        controller: _pageController, // 페이지를 컨트롤할 PageController
        scrollDirection: Axis.vertical, // 스크롤 방향을 수직으로 설정
        onPageChanged: _onPageChanged, // 페이지 변경 시 호출될 메서드
        itemCount: videos.length, // 비디오 목록의 길이에 따라 페이지 수 결정
        itemBuilder: (context, index) => VideoPost( // 각 비디오 항목을 렌더링
          onVideoFinished: _onVideoFinished, // 비디오 재생 완료 시 호출될 메서드
          index: index, // 현재 비디오의 인덱스
        ),
      ),
    ),
  );
}

이 코드에서는 timelineProvider의 상태를 ref.watch를 통해 구독하고 있으며, .when 메서드를 사용해 해당 상태가 loading, error, data 중 어느 것인지에 따라 다른 위젯을 렌더링합니다. 이러한 방식으로 비동기 데이터 로딩 상태를 관리하고 사용자에게 적절한 피드백(로딩 인디케이터, 에러 메시지, 비디오 목록)을 제공할 수 있습니다. 이는 비동기 작업의 결과를 처리하고 UI를 업데이트하는 효율적인 방법을 제공합니다.

profile
공부하는 개발자

0개의 댓글