Skip to content

Commit

Permalink
feat: Stream 생성 샘플
Browse files Browse the repository at this point in the history
  • Loading branch information
junsuk5 committed Apr 23, 2024
1 parent 46cdca2 commit fd64686
Show file tree
Hide file tree
Showing 10 changed files with 240 additions and 0 deletions.
18 changes: 18 additions & 0 deletions lib/11_stream_world_time_api/core/router.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import 'package:go_router/go_router.dart';
import 'package:learn_flutter_together/11_stream_world_time_api/di/di_setup.dart';
import 'package:learn_flutter_together/11_stream_world_time_api/presentation/main_screen.dart';
import 'package:learn_flutter_together/11_stream_world_time_api/presentation/main_view_model.dart';
import 'package:provider/provider.dart';

// GoRouter configuration
final router11 = GoRouter(
routes: [
GoRoute(
path: '/',
builder: (context, state) => ChangeNotifierProvider(
create: (_) => getIt<MainViewModel>(),
child: const MainScreen(),
),
),
],
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import '../../domain/model/time.dart';
import '../../domain/repository/time_repository.dart';

class MockTimeRepositoryImpl implements TimeRepository {
final _times = [
Time(
timezone: 'Asia/Seoul',
unixTime: 1713835159,
utcDateTime: DateTime.fromMillisecondsSinceEpoch(1713835159),
utcOffset: '+09:00',
),
Time(
timezone: 'Asia/Seoul',
unixTime: 1813835159,
utcDateTime: DateTime.fromMillisecondsSinceEpoch(1813835159),
utcOffset: '+09:00',
),
Time(
timezone: 'Asia/Seoul',
unixTime: 1913835159,
utcDateTime: DateTime.fromMillisecondsSinceEpoch(1913835159),
utcOffset: '+09:00',
),
];

int _count = 0;

@override
Future<Time> getTime() async {
if (_count >= _times.length) {
_count = 0;
}
return _times[_count++];
}
}
20 changes: 20 additions & 0 deletions lib/11_stream_world_time_api/di/di_setup.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import 'package:get_it/get_it.dart';
import 'package:learn_flutter_together/11_stream_world_time_api/presentation/main_view_model.dart';

import '../data/repository/mock_time_repository_impl.dart';
import '../domain/model/time.dart';
import '../domain/repository/time_repository.dart';
import '../domain/use_case/fetch_periodic_time_use_case.dart';

final getIt = GetIt.instance;

void diSetup() {
getIt.registerSingleton<TimeRepository>(MockTimeRepositoryImpl());
getIt.registerSingleton<FetchPeriodicTimeUseCase>(
FetchPeriodicTimeUseCase(
second: 1,
timeRepository: getIt(),
),
);
getIt.registerFactory(() => MainViewModel(fetchPeriodicTimeUseCase: getIt()));
}
17 changes: 17 additions & 0 deletions lib/11_stream_world_time_api/domain/model/time.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import 'package:freezed_annotation/freezed_annotation.dart';

part 'time.freezed.dart';

part 'time.g.dart';

@freezed
class Time with _$Time {
const factory Time({
required String timezone,
required int unixTime,
required DateTime utcDateTime,
required String utcOffset,
}) = _Time;

factory Time.fromJson(Map<String, Object?> json) => _$TimeFromJson(json);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import '../model/time.dart';

abstract interface class TimeRepository {
Future<Time> getTime();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import 'dart:async';

import 'package:learn_flutter_together/11_stream_world_time_api/domain/repository/time_repository.dart';

import '../model/time.dart';

class FetchPeriodicTimeUseCase {
final int _second;
final TimeRepository _timeRepository;

final _streamController = StreamController<Time>();

FetchPeriodicTimeUseCase({
required int second,
required TimeRepository timeRepository,
}) : _second = second,
_timeRepository = timeRepository;

Stream<Time> execute() {
Timer.periodic(Duration(seconds: _second), (timer) {
_timeRepository.getTime().then((time) {
_streamController.add(time);
});
});

return _streamController.stream;
}
}
25 changes: 25 additions & 0 deletions lib/11_stream_world_time_api/main.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import 'package:flutter/material.dart';
import 'package:learn_flutter_together/11_stream_world_time_api/core/router.dart';
import 'package:learn_flutter_together/11_stream_world_time_api/di/di_setup.dart';

void main() {
diSetup();
runApp(const MyApp());
}

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

// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routerConfig: router11,
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
);
}
}
24 changes: 24 additions & 0 deletions lib/11_stream_world_time_api/presentation/main_screen.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import 'package:flutter/material.dart';
import 'package:learn_flutter_together/11_stream_world_time_api/presentation/main_view_model.dart';
import 'package:provider/provider.dart';

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

@override
Widget build(BuildContext context) {
final viewModel = context.watch<MainViewModel>();

return Scaffold(
appBar: AppBar(
title: const Text('Stream 샘플'),
),
body: Center(
child: Text(
viewModel.time.toString(),
style: const TextStyle(fontSize: 40),
),
),
);
}
}
42 changes: 42 additions & 0 deletions lib/11_stream_world_time_api/presentation/main_view_model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import 'dart:async';

import 'package:flutter/material.dart';
import 'package:learn_flutter_together/11_stream_world_time_api/domain/use_case/fetch_periodic_time_use_case.dart';

import '../domain/model/time.dart';

class MainViewModel with ChangeNotifier {
final FetchPeriodicTimeUseCase _fetchPeriodicTimeUseCase;

Time? _time;

StreamSubscription<Time>? _subscription;

Time get time =>
_time ??
Time(
timezone: 'null',
unixTime: 0,
utcDateTime: DateTime.now(),
utcOffset: 'null',
);

MainViewModel({
required FetchPeriodicTimeUseCase fetchPeriodicTimeUseCase,
}) : _fetchPeriodicTimeUseCase = fetchPeriodicTimeUseCase {
fetchTime();
}

void fetchTime() {
_subscription = _fetchPeriodicTimeUseCase.execute().listen((time) {
_time = time;
notifyListeners();
});
}

@override
void dispose() {
_subscription?.cancel();
super.dispose();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:learn_flutter_together/11_stream_world_time_api/di/di_setup.dart';
import 'package:learn_flutter_together/11_stream_world_time_api/domain/model/time.dart';
import 'package:learn_flutter_together/11_stream_world_time_api/domain/use_case/fetch_periodic_time_use_case.dart';

void main() {
setUp(() => diSetup());

test('FetchPeriodicTimeUseCase Test', () async {
// final timeRepository = getIt<TimeRepository>();
//
// final useCase = FetchPeriodicTimeUseCase(
// second: 1,
// timeRepository: timeRepository,
// );
final useCase = getIt<FetchPeriodicTimeUseCase>();

useCase.execute().listen(expectAsync1(
(event) {
print(event);
expect(event, isA<Time>());
},
count: 3,
));
});
}

0 comments on commit fd64686

Please sign in to comment.