Skip to content
21 changes: 18 additions & 3 deletions src/mobile/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import 'package:airqo/src/app/dashboard/repository/dashboard_repository.dart';
import 'package:airqo/src/app/dashboard/repository/forecast_repository.dart';
import 'package:airqo/src/app/dashboard/repository/country_repository.dart';
import 'package:airqo/src/app/learn/bloc/kya_bloc.dart';
import 'package:airqo/src/app/learn/repository/kya_repository.dart';
import 'package:airqo/src/app/learn/repository/learn_repository.dart';
import 'package:airqo/src/app/learn/services/learn_sync_service.dart';
import 'package:airqo/src/app/map/bloc/map_bloc.dart';
import 'package:airqo/src/app/map/repository/map_repository.dart';
import 'package:airqo/src/app/other/places/bloc/google_places_bloc.dart';
Expand Down Expand Up @@ -89,7 +90,7 @@ void main() async {
authRepository: authImpl,
socialAuthRepository: authImpl,
userRepository: UserImpl(),
kyaRepository: KyaImpl(),
kyaRepository: LearnRepositoryImpl(),
themeRepository: ThemeImpl(),
mapRepository: MapImpl(),
forecastRepository: ForecastImpl(),
Expand All @@ -113,7 +114,7 @@ class AirqoMobile extends StatelessWidget {
final UserRepository userRepository;
final MapRepository mapRepository;
final ThemeRepository themeRepository;
final KyaRepository kyaRepository;
final LearnRepository kyaRepository;
final GooglePlacesRepository googlePlacesRepository;
final DashboardRepository dashboardRepository;

Expand Down Expand Up @@ -248,9 +249,16 @@ class _DeciderState extends State<Decider> with WidgetsBindingObserver {
WidgetsBinding.instance.addPostFrameCallback((_) {
AutoUpdateService().initialize(navigatorKey);
_fetchCountries();
_initLearnGuestSession();
});
}

void _initLearnGuestSession() {
LearnSyncService.instance.ensureGuestSession().then((_) {
LearnSyncService.instance.syncPendingProgress();
}).catchError((_) {});
Comment thread
Mozart299 marked this conversation as resolved.
}

void _fetchCountries() async {
try {
await CountryRepository().fetchCountries();
Expand Down Expand Up @@ -309,6 +317,13 @@ class _DeciderState extends State<Decider> with WidgetsBindingObserver {
if (!_hasRequestedUserLoad) {
_hasRequestedUserLoad = true;
context.read<UserBloc>().add(LoadUser());
AuthHelper.refreshTokenIfNeeded().then((token) {
if (token != null) {
LearnSyncService.instance
.linkProgressToAccount(token)
.catchError((_) {});
}
}).catchError((_) {});
}
} else if (authState is GuestUser ||
authState is AuthLoadingError ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ class LocationServiceManager with UiLoggy {

final position = await Geolocator.getCurrentPosition(
locationSettings: const LocationSettings(
timeLimit: Duration(seconds: 10),
timeLimit: Duration(seconds: 5),
),
);
final placemarks =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ class _AnalyticsSpecificsState extends State<AnalyticsSpecifics> {
'assets/icons/share-icon.svg',
width: 18,
height: 18,
colorFilter: const ColorFilter.mode(
colorFilter: ColorFilter.mode(
AppColors.primaryColor,
BlendMode.srcIn,
),
Expand Down
2 changes: 1 addition & 1 deletion src/mobile/lib/src/app/dashboard/widgets/nearby_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ class _NearbyViewState extends State<NearbyView> with UiLoggy {

Future<void> _updateNearbyLocations() async {
if (_userPosition == null) {
loggy.warning('Cannot filter nearby locations: user position unavailable');
loggy.info('Skipping nearby filter: position not yet available');
return;
}

Expand Down
37 changes: 23 additions & 14 deletions src/mobile/lib/src/app/dashboard/widgets/view_selector.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:airqo/src/app/dashboard/models/country_model.dart';
import 'package:airqo/src/app/shared/widgets/country_button';
import 'package:airqo/src/app/shared/widgets/loading_widget.dart';
import 'package:airqo/src/app/shared/widgets/translated_text.dart';
import 'package:airqo/src/app/shared/widgets/translated_tooltip.dart';
import 'package:flutter/material.dart';
Expand Down Expand Up @@ -169,20 +170,28 @@ class _ViewSelectorState extends State<ViewSelector> {
),
],
SizedBox(width: 8),
...sortedCountries.map((country) => Padding(
padding: const EdgeInsets.only(right: 8),
child: _buildCountryButton(
context,
flag: country.flag,
name: country.countryName,
isSelected: widget.currentView == DashboardView.country &&
widget.selectedCountry == country.countryName,
onTap: () => widget.onViewChanged(DashboardView.country,
country: country.countryName),
isUserCountry: widget.userCountry?.toLowerCase() ==
country.countryName.toLowerCase(),
),
)),
if (widget.activeCountries == null) ...[
const SizedBox(width: 8),
ShimmerContainer(height: 40, borderRadius: 30, width: 90),
const SizedBox(width: 8),
ShimmerContainer(height: 40, borderRadius: 30, width: 110),
const SizedBox(width: 8),
ShimmerContainer(height: 40, borderRadius: 30, width: 100),
] else
...sortedCountries.map((country) => Padding(
padding: const EdgeInsets.only(right: 8),
child: _buildCountryButton(
context,
flag: country.flag,
name: country.countryName,
isSelected: widget.currentView == DashboardView.country &&
widget.selectedCountry == country.countryName,
onTap: () => widget.onViewChanged(DashboardView.country,
country: country.countryName),
isUserCountry: widget.userCountry?.toLowerCase() ==
country.countryName.toLowerCase(),
),
)),
],
),
);
Expand Down
46 changes: 22 additions & 24 deletions src/mobile/lib/src/app/learn/bloc/kya_bloc.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import 'package:airqo/src/app/learn/models/lesson_response_model.dart';
import 'package:airqo/src/app/learn/repository/kya_repository.dart';
import 'package:airqo/src/app/shared/services/cache_manager.dart';
import 'package:airqo/src/app/learn/models/learn_v2_catalog.dart';
import 'package:airqo/src/app/learn/repository/learn_repository.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:loggy/loggy.dart';
Expand All @@ -9,39 +8,39 @@ part 'kya_event.dart';
part 'kya_state.dart';

class KyaBloc extends Bloc<KyaEvent, KyaState> with UiLoggy {
final KyaRepository repository;
final CacheManager _cacheManager = CacheManager();
final LearnRepository repository;

KyaBloc(this.repository) : super(KyaInitial()) {
on<LoadLessons>(_onLoadLessons);
on<RefreshLessons>(_onRefreshLessons);
}

Future<void> _onLoadLessons(LoadLessons event, Emitter<KyaState> emit) async {
Future<void> _onLoadLessons(
LoadLessons event, Emitter<KyaState> emit) async {
try {
emit(LessonsLoading());

final LessonResponseModel model =
await repository.fetchLessons(forceRefresh: event.forceRefresh);
final LearnV2CatalogResponse model =
await repository.fetchCatalog(forceRefresh: event.forceRefresh);

emit(LessonsLoaded(model));
} catch (e) {
loggy.error('Error loading lessons: $e');
loggy.error('Error loading Learn catalog: $e');

// Try to get cached data directly from the repository
try {
final LessonResponseModel? cachedModel = await _getCachedLessonsData();
final LearnV2CatalogResponse? cachedModel =
await _getCachedCatalog();

emit(LessonsLoadingError(
message: e.toString(),
cachedModel: cachedModel,
isOffline: !_cacheManager.isConnected,
isOffline: repository.isOffline,
));
} catch (cacheError) {
loggy.error('Error fetching cached lessons: $cacheError');
loggy.error('Error fetching cached catalog: $cacheError');
emit(LessonsLoadingError(
message: e.toString(),
isOffline: !_cacheManager.isConnected,
isOffline: repository.isOffline,
));
}
}
Expand All @@ -52,34 +51,33 @@ class KyaBloc extends Bloc<KyaEvent, KyaState> with UiLoggy {
emit(LessonsRefreshing(currentModel: event.currentModel));

try {
final LessonResponseModel model =
await repository.fetchLessons(forceRefresh: true);
final LearnV2CatalogResponse model =
await repository.fetchCatalog(forceRefresh: true);

emit(LessonsLoaded(model));
} catch (e) {
loggy.error('Error refreshing lessons: $e');
loggy.error('Error refreshing Learn catalog: $e');

if (event.currentModel != null) {
// Return to loaded state with existing data
emit(LessonsLoaded(event.currentModel!));
} else {
// Try to get cached data
final LessonResponseModel? cachedModel = await _getCachedLessonsData();
final LearnV2CatalogResponse? cachedModel =
await _getCachedCatalog();

emit(LessonsLoadingError(
message: e.toString(),
cachedModel: cachedModel,
isOffline: !_cacheManager.isConnected,
isOffline: repository.isOffline,
));
}
}
}

Future<LessonResponseModel?> _getCachedLessonsData() async {
Future<LearnV2CatalogResponse?> _getCachedCatalog() async {
try {
return await (repository as KyaImpl).getCachedLessonsData();
return await repository.getCachedCatalog();
} catch (e) {
loggy.error('Error getting cached lessons data: $e');
loggy.error('Error getting cached Learn catalog: $e');
return null;
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/mobile/lib/src/app/learn/bloc/kya_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ class LoadLessons extends KyaEvent {
}

class RefreshLessons extends KyaEvent {
final LessonResponseModel? currentModel;
final LearnV2CatalogResponse? currentModel;

const RefreshLessons({this.currentModel});

@override
List<Object?> get props => [currentModel];
}
14 changes: 7 additions & 7 deletions src/mobile/lib/src/app/learn/bloc/kya_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,27 @@ class KyaInitial extends KyaState {}
class LessonsLoading extends KyaState {}

class LessonsRefreshing extends KyaState {
final LessonResponseModel? currentModel;
final LearnV2CatalogResponse? currentModel;

const LessonsRefreshing({this.currentModel});

@override
List<Object?> get props => [currentModel];
}

class LessonsLoaded extends KyaState {
final LessonResponseModel model;
final LearnV2CatalogResponse model;
final bool fromCache;

const LessonsLoaded(this.model, {this.fromCache = false});

@override
List<Object> get props => [model, fromCache];
}

class LessonsLoadingError extends KyaState {
final String message;
final LessonResponseModel? cachedModel;
final LearnV2CatalogResponse? cachedModel;
final bool isOffline;

const LessonsLoadingError({
Expand Down
Loading
Loading