Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions assets/svg/ic_tabler_world.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions lib/core/app_assets.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class AppAssets {
static const String icClose = 'assets/svg/ic_close.svg';
static const String icEmptyProfile = 'assets/svg/ic_empty_profile.svg';
static const String icGroup = 'assets/svg/ic_group.svg';
static const String icTablerWorld = 'assets/svg/ic_tabler_world.svg';

// Logo
static const String icLogoWhite = 'assets/svg/ic_logo_white.svg';
Expand Down
18 changes: 15 additions & 3 deletions lib/core/app_utils.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'dart:ui';

import 'package:arttrip/core/app_consts.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

class AppUtil {
const AppUtil._();
Expand All @@ -17,7 +16,7 @@ class AppUtil {
return List.generate(7, (index) => sunday.add(Duration(days: index)));
}

/// 주간 요일
/// 일자별 요일
static String weekdayLabel({required DateTime date, required Locale locale}) {
var isKorean = locale.languageCode == 'ko';
var labels = isKorean ? AppConsts.weekDaysKo : AppConsts.weekDaysEn;
Expand All @@ -26,6 +25,13 @@ class AppUtil {
return labels[date.weekday % 7];
}

/// 일 ~ 월 요일 리스트
static List<String> getLocalizedWeekdays(Locale locale) {
var isKorean = locale.languageCode == 'ko';
var labels = isKorean ? AppConsts.weekDaysKo : AppConsts.weekDaysEn;
return labels;
}

/// '2025-12-25' 포맷 반환
static String formatDateYMD(DateTime date) {
var year = date.year.toString().padLeft(4, '0');
Expand All @@ -34,4 +40,10 @@ class AppUtil {

return '$year-$month-$day';
}

static String getLanguage(BuildContext context) {
var locale = Localizations.localeOf(context);
var language = locale.languageCode == 'ko' ? 'ko' : 'en';
return language;
}
}
2 changes: 1 addition & 1 deletion lib/features/exhibit/data/models/exhibit_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ abstract class ExhibitModel with _$ExhibitModel {
String? hallName,
String? countryName,
String? regionName,
@Default(false) bool isFavorite, // TODO: 컬럼명 확인 필요
@Default(false) bool favorite,
}) = _ExhibitModel;

factory ExhibitModel.fromJson(Map<String, dynamic> json) =>
Expand Down
2 changes: 1 addition & 1 deletion lib/features/exhibit/viewmodels/exhibit_viewmodel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class ExhibitViewModel with ChangeNotifier {
var id = exhibit.exhibitId;
if (id == null) continue;

_favoriteMap.putIfAbsent(id, () => exhibit.isFavorite);
_favoriteMap.putIfAbsent(id, () => exhibit.favorite);
}
}

Expand Down
80 changes: 59 additions & 21 deletions lib/features/home/home_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:arttrip/features/home/views/personalized_exhibits_view.dart';
import 'package:arttrip/features/home/views/regional_exhibits_view.dart';
import 'package:arttrip/features/home/views/today_exhibits_recommendation_view.dart';
import 'package:arttrip/features/home/views/weekly_exhibits_schedule_view.dart';
import 'package:arttrip/features/home/widgets/date_filter_bottom_sheet.dart';
import 'package:arttrip/shared/utils/text/arttrip_text.dart';
import 'package:arttrip/shared/widgets/alert_badge.dart';
import 'package:flutter/material.dart';
Expand Down Expand Up @@ -83,27 +84,33 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SvgPicture.asset(AppAssets.icLogoBlack, width: 88.w, height: 28.h),
Row(
spacing: 20.w,
children: [
const AlertBadge(path: '/alerts'),
GestureDetector(
onTap: () {},
child: SvgPicture.asset(
AppAssets.icCalendar,
width: 24.w,
height: 24.w,
),
),
GestureDetector(
onTap: () {},
child: SvgPicture.asset(
AppAssets.icSearch,
width: 24.w,
height: 24.w,
),
),
],
Selector<HomeViewModel, bool>(
selector: (_, vm) => vm.isDomestic,
builder: (context, isDomestic, _) {
return Row(
spacing: 20.w,
children: [
const AlertBadge(path: '/alerts'),
if (!isDomestic)
GestureDetector(
onTap: () => _showDateFilterBottomSheet(),
child: SvgPicture.asset(
AppAssets.icCalendar,
width: 24.w,
height: 24.w,
),
),
GestureDetector(
onTap: () {},
child: SvgPicture.asset(
AppAssets.icSearch,
width: 24.w,
height: 24.w,
),
),
],
);
},
),
],
),
Expand Down Expand Up @@ -164,4 +171,35 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
),
);
}

void _showDateFilterBottomSheet() {
showModalBottomSheet(
context: context,
useRootNavigator: true,
shape: RoundedRectangleBorder(
borderRadius: BorderRadiusGeometry.only(
topLeft: Radius.circular(16.r),
topRight: Radius.circular(16.r),
),
),
backgroundColor: AppColors.subLightGray,
isScrollControlled: true,
builder:
(_) => Selector<HomeViewModel, List<String>?>(
selector: (_, vm) => vm.overseasCountriesCache,
builder: (context, overseasCountries, _) {
if (overseasCountries == null) {
return Container(
height: MediaQuery.of(context).size.height / 2,
alignment: Alignment.center,
child: const CircularProgressIndicator(
color: AppColors.primary300,
),
);
}
return DateFilterBottomSheet(overseasCountries);
},
),
);
}
}
10 changes: 7 additions & 3 deletions lib/features/home/home_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import 'package:arttrip/core/app_utils.dart';
import 'package:arttrip/core/network/dio_client.dart';
import 'package:arttrip/features/exhibit/data/models/exhibit_model.dart';
import 'package:arttrip/shared/models/base_result_model.dart';
import 'package:arttrip/shared/models/region_model.dart';

abstract class HomeRepository {
Future<List<String>?> fetchOverseasCountries();
Future<List<String>?> fetchDomesticRegions();
Future<List<RegionModel>?> fetchDomesticRegions();
Future<List<ExhibitModel>?> fetchTodayExhibitRecommendations({
required bool isDomestic,
String? country,
Expand Down Expand Up @@ -55,18 +56,21 @@ class HomeRepositoryImpl implements HomeRepository {
}

@override
Future<List<String>?> fetchDomesticRegions() async {
Future<List<RegionModel>?> fetchDomesticRegions() async {
try {
var response = await _dio.get('/exhibit/domestic');
var model = BaseResultModel.fromJson(response.dataOrNull);

if (model.result is! List) {
AppUtil.debugLog(
'fetchDomesticRegions type inconsistency: ${model.result.runtimeType}',
);
return null;
}

return model.result.map<String>((e) => e.toString()).toList();
return model.result
.map<RegionModel>((e) => RegionModel.fromJson(e))
.toList();
} catch (e) {
AppUtil.debugLog('fetchDomesticRegions: $e');
}
Expand Down
3 changes: 2 additions & 1 deletion lib/features/home/home_repository_hybrid.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:arttrip/core/app_consts.dart';
import 'package:arttrip/features/exhibit/data/models/exhibit_model.dart';
import 'package:arttrip/features/home/home_repository.dart';
import 'package:arttrip/shared/models/region_model.dart';

class HomeRepositoryHybrid implements HomeRepository {
HomeRepositoryHybrid({required this.mock, required this.api});
Expand All @@ -17,7 +18,7 @@ class HomeRepositoryHybrid implements HomeRepository {
}

@override
Future<List<String>?> fetchDomesticRegions() {
Future<List<RegionModel>?> fetchDomesticRegions() {
if (AppConsts.useMock) {
return mock.fetchDomesticRegions();
}
Expand Down
12 changes: 10 additions & 2 deletions lib/features/home/home_repository_mock.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:arttrip/core/app_consts.dart';
import 'package:arttrip/core/app_urls.dart';
import 'package:arttrip/features/exhibit/data/models/exhibit_model.dart';
import 'package:arttrip/features/home/home_repository.dart';
import 'package:arttrip/shared/models/region_model.dart';

class HomeRepositoryMockImpl implements HomeRepository {
@override
Expand All @@ -13,11 +14,18 @@ class HomeRepositoryMockImpl implements HomeRepository {
}

@override
Future<List<String>?> fetchDomesticRegions() async {
Future<List<RegionModel>?> fetchDomesticRegions() async {
await Future.delayed(
const Duration(milliseconds: AppConsts.mockLoadingDelayMs),
);
return ['서울', '경기', '충청', '강원', '전라', '경상', '제주'];
return [
RegionModel(region: '서울', imageUrl: AppUrls.posterUrlMock),
RegionModel(region: '경기', imageUrl: AppUrls.posterUrlMock),
RegionModel(region: '전라', imageUrl: AppUrls.posterUrlMock),
RegionModel(region: '제주', imageUrl: AppUrls.posterUrlMock),
RegionModel(region: '경상', imageUrl: AppUrls.posterUrlMock),
RegionModel(region: '강원', imageUrl: AppUrls.posterUrlMock),
];
}

@override
Expand Down
10 changes: 6 additions & 4 deletions lib/features/home/home_viewmodel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:arttrip/core/extensions.dart';
import 'package:arttrip/features/exhibit/data/models/exhibit_model.dart';
import 'package:arttrip/features/exhibit/viewmodels/exhibit_viewmodel.dart';
import 'package:arttrip/features/home/home_repository.dart';
import 'package:arttrip/shared/models/region_model.dart';
import 'package:arttrip/shared/widgets/async_view.dart';
import 'package:flutter/material.dart';

Expand All @@ -15,7 +16,7 @@ class HomeViewModel with ChangeNotifier {
final HomeRepository homeRepository;

AsyncState<List<String>> overseasCountries = const AsyncState.loading();
AsyncState<List<String>> domesticRegions = const AsyncState.loading();
AsyncState<List<RegionModel>> domesticRegions = const AsyncState.loading();
AsyncState<List<ExhibitModel>> todayExhibitRecommendations =
const AsyncState.loading();
Map<String, AsyncState<List<String>>> genres = {
Expand All @@ -42,7 +43,7 @@ class HomeViewModel with ChangeNotifier {
AsyncState<List<DateTime>> weeklyCalendar = const AsyncState.loading();

List<String>? _overseasCountriesCache;
List<String>? _domesticRegionsCache;
List<RegionModel>? _domesticRegionsCache;
final Map<String, List<ExhibitModel>> _todayExhibitRecommendationsCache = {};
final Map<String, List<ExhibitModel>> _personalizedExhibitsCache = {};
List<DateTime>? _weeklyCalendarCache;
Expand All @@ -64,7 +65,8 @@ class HomeViewModel with ChangeNotifier {
String get locationType =>
_isDomestic ? LocationType.domestic.name : LocationType.overseas.name;

List<String>? get domesticRegionsCache => _domesticRegionsCache;
List<String>? get overseasCountriesCache => _overseasCountriesCache;
List<RegionModel>? get domesticRegionsCache => _domesticRegionsCache;

set isDomestic(bool value) {
_isDomestic = value;
Expand Down Expand Up @@ -176,7 +178,7 @@ class HomeViewModel with ChangeNotifier {
var key = _isDomestic ? LocationType.domestic.name : _selectedLocation;
if (_todayExhibitRecommendationsCache[key] != null) {
todayExhibitRecommendations = AsyncState.success(
_todayExhibitRecommendationsCache[_selectedLocation]!,
_todayExhibitRecommendationsCache[key]!,
);
notifyListeners();
return;
Expand Down
11 changes: 6 additions & 5 deletions lib/features/home/regional_exhibits_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:arttrip/core/app_assets.dart';
import 'package:arttrip/core/app_colors.dart';
import 'package:arttrip/core/extensions.dart';
import 'package:arttrip/features/home/home_viewmodel.dart';
import 'package:arttrip/shared/models/region_model.dart';
import 'package:arttrip/shared/utils/text/arttrip_text.dart';
import 'package:arttrip/shared/widgets/common_appbar.dart';
import 'package:flutter/material.dart';
Expand Down Expand Up @@ -133,7 +134,7 @@ class _RegionalExhibitsPageState extends State<RegionalExhibitsPage> {
ArtTripText.pretendard().body01Bold().build().text(
context.l10n.domestic,
),
Selector<HomeViewModel, List<String>>(
Selector<HomeViewModel, List<RegionModel>>(
selector: (_, vm) => vm.domesticRegionsCache!,
builder: (context, domesticRegionsCache, _) {
return Wrap(
Expand All @@ -143,10 +144,10 @@ class _RegionalExhibitsPageState extends State<RegionalExhibitsPage> {
index,
) {
var item = domesticRegionsCache[index];
var isSelected = selectedRegion == item;
var isSelected = selectedRegion == item.region;
return GestureDetector(
onTap: () {
_regionName.value = item;
_regionName.value = item.region;
Navigator.pop(context);
},
child: Container(
Expand All @@ -167,11 +168,11 @@ class _RegionalExhibitsPageState extends State<RegionalExhibitsPage> {
.body01Bold()
.color(AppColors.textWhite)
.build()
.text(item)
.text(item.region)
: ArtTripText.pretendard()
.body01Light()
.build()
.text(item),
.text(item.region),
),
);
}),
Expand Down
Loading