diff --git a/.gitignore b/.gitignore index cbfc4963..7502fbb7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ -# Custom -.fvm/ +# Do not remove or rename entries in this file, only add new ones +# See https://github.com/flutter/flutter/issues/128635 for more context. # Miscellaneous *.class @@ -23,7 +23,7 @@ .classpath .project .settings/ -.vscode/ +.vscode/* # Flutter repo-specific /bin/cache/ @@ -35,6 +35,7 @@ /dev/bots/android_tools/ /dev/devicelab/ABresults*.json /dev/docs/doc/ +/dev/docs/api_docs.zip /dev/docs/flutter.docs.zip /dev/docs/lib/ /dev/docs/pubspec.yaml @@ -54,6 +55,7 @@ analysis_benchmark.json .flutter-plugins-dependencies **/generated_plugin_registrant.dart .packages +.pub-preload-cache/ .pub-cache/ .pub/ build/ @@ -64,7 +66,7 @@ unlinked_spec.ds # Android related **/android/**/gradle-wrapper.jar -**/android/.gradle +.gradle/ **/android/captures/ **/android/gradlew **/android/gradlew.bat @@ -104,7 +106,21 @@ unlinked_spec.ds **/ios/Runner/GeneratedPluginRegistrant.* # macOS +**/Flutter/ephemeral/ +**/Pods/ **/macos/Flutter/GeneratedPluginRegistrant.swift +**/macos/Flutter/ephemeral +**/xcuserdata/ + +# Windows +**/windows/flutter/generated_plugin_registrant.cc +**/windows/flutter/generated_plugin_registrant.h +**/windows/flutter/generated_plugins.cmake + +# Linux +**/linux/flutter/generated_plugin_registrant.cc +**/linux/flutter/generated_plugin_registrant.h +**/linux/flutter/generated_plugins.cmake # Coverage coverage/ @@ -118,4 +134,5 @@ app.*.symbols !**/ios/**/default.pbxuser !**/ios/**/default.perspectivev3 !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages -!/dev/ci/**/Gemfile.lock \ No newline at end of file +!/dev/ci/**/Gemfile.lock +!.vscode/settings.json \ No newline at end of file diff --git a/.metadata b/.metadata index be749857..9abf315c 100644 --- a/.metadata +++ b/.metadata @@ -1,10 +1,36 @@ # This file tracks properties of this Flutter project. # Used by Flutter tool to assess capabilities and perform upgrades etc. # -# This file should be version controlled and should not be manually edited. +# This file should be version controlled. version: - revision: adc687823a831bbebe28bdccfac1a628ca621513 + revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 channel: stable project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 + base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 + - platform: linux + create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 + base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 + - platform: macos + create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 + base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 + - platform: windows + create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 + base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..c5f3f6b9 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "java.configuration.updateBuildConfiguration": "interactive" +} \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle index 86c61dc8..de9cdb14 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,12 +1,12 @@ buildscript { - ext.kotlin_version = '1.7.10' + ext.kotlin_version = '1.9.10' repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.2.0' + classpath 'com.android.tools.build:gradle:7.3.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" classpath 'com.google.gms:google-services:4.3.15' @@ -28,6 +28,6 @@ subprojects { project.evaluationDependsOn(':app') } -task clean(type: Delete) { +tasks.register("clean", Delete) { delete rootProject.buildDir } diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index f903c591..893d988d 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri Jun 23 08:50:38 CEST 2017 +#Sat Feb 18 16:22:23 MSK 2023 distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip \ No newline at end of file +zipStoreBase=GRADLE_USER_HOME diff --git a/lib/data/datasources/news_remote.dart b/lib/data/datasources/news_remote.dart index 340b3837..86340e90 100644 --- a/lib/data/datasources/news_remote.dart +++ b/lib/data/datasources/news_remote.dart @@ -3,34 +3,40 @@ import 'package:rtu_mirea_app/common/errors/exceptions.dart'; import 'package:rtu_mirea_app/data/models/news_item_model.dart'; abstract class NewsRemoteData { - Future> getNews(int offset, int limit, bool isImportant, + Future> getNews(int page, int pageSize, bool isImportant, [String? tag]); Future> getTags(); } class NewsRemoteDataImpl extends NewsRemoteData { - static const _apiUrl = "https://cms.mirea.ninja/api"; + // Доступны методы: getNews, getEvents, getAds. + static const _apiUrl = "https://mirea.ru/api/oCoGUGuMhQzPEDJYF6Qy.php"; final Dio httpClient; NewsRemoteDataImpl({required this.httpClient}); @override - Future> getNews(int offset, int limit, bool isImportant, + Future> getNews(int page, int pageSize, bool isImportant, [String? tag]) async { - final String tagsFilter = - tag != null ? "&filters[tags][name][\$eq]=$tag" : ""; - final String requestUrl = - '$_apiUrl/announcements?populate=*&pagination[limit]=$limit&pagination[start]=$offset&sort=date:DESC&filters[isImportant][\$eq]=${isImportant.toString()}$tagsFilter'; + String params = + 'nPageSize=$pageSize&iNumPage=$page${tag != null ? "&tag=$tag" : ""}'; - final response = await httpClient.get(requestUrl); + Response response; + if (!isImportant) { + response = await httpClient.get('$_apiUrl?method=getNews&$params'); + } else { + response = await httpClient.get('$_apiUrl?method=getAds&$params'); + } if (response.statusCode == 200) { Map responseBody = response.data; - return responseBody["data"] - .map( - (newsItem) => NewsItemModel.fromJson(newsItem["attributes"])) + + List news = responseBody["result"] + .map((newsItem) => NewsItemModel.fromJson(newsItem)) .toList(); + + return news; } else { throw ServerException('Response status code is $response.statusCode'); } @@ -38,15 +44,19 @@ class NewsRemoteDataImpl extends NewsRemoteData { @override Future> getTags() async { - final response = await httpClient.get('$_apiUrl/tags'); + final response = await httpClient.get('$_apiUrl?method=getNewsTags'); if (response.statusCode == 200) { Map responseBody = response.data; - List tags = []; - tags = List.from( - responseBody["data"].map((x) => x['attributes']['name'])); - return tags; + final tagsResponse = + responseBody["result"].map((e) => e as Map); + + final tags = tagsResponse + .where((element) => int.parse(element["CNT"]) > 3) + .map((e) => e["NAME"]!); + + return tags.toList().cast(); } else { throw ServerException('Response status code is $response.statusCode'); } diff --git a/lib/data/models/news_item_model.dart b/lib/data/models/news_item_model.dart index 840f01ac..780cc571 100644 --- a/lib/data/models/news_item_model.dart +++ b/lib/data/models/news_item_model.dart @@ -1,7 +1,6 @@ +import 'package:intl/intl.dart'; import 'package:rtu_mirea_app/domain/entities/news_item.dart'; -import 'strapi_media_model.dart'; - class NewsItemModel extends NewsItem { const NewsItemModel({ required title, @@ -9,29 +8,26 @@ class NewsItemModel extends NewsItem { required date, required images, required tags, - required isImportant, }) : super( title: title, text: text, date: date, images: images, tags: tags, - isImportant: isImportant, ); factory NewsItemModel.fromJson(Map json) { return NewsItemModel( - title: json['title'], - text: json['text'], - date: DateTime.parse(json['date']), - images: List.from(json["images"]["data"] - .map((x) => StrapiMediaModel.fromJson(x["attributes"]))), + title: json['NAME'], + text: json['DETAIL_TEXT'], + date: DateFormat("dd.MM.yyyy").parse(json['DATE_ACTIVE_FROM']), + images: List.from(json['PROPERTY_MY_GALLERY_VALUE'] ?? []) + ..add(json['DETAIL_PICTURE']), tags: List.from( - json["tags"]["data"].map((x) => x["attributes"]['name'])), - isImportant: json['isImportant'], + json['TAGS'].toString().split(',').map((x) => x.trim())), ); } @override - List get props => [title, text, date, images, tags, isImportant]; + List get props => [title, text, date, images, tags]; } diff --git a/lib/data/repositories/news_repository_impl.dart b/lib/data/repositories/news_repository_impl.dart index d259558c..6b735af2 100644 --- a/lib/data/repositories/news_repository_impl.dart +++ b/lib/data/repositories/news_repository_impl.dart @@ -17,12 +17,12 @@ class NewsRepositoryImpl implements NewsRepository { @override Future>> getNews( - int offset, int limit, bool isImportant, + int page, int pageSize, bool isImportant, [String? tag]) async { if (await connectionChecker.hasConnection) { try { final newsList = - await remoteDataSource.getNews(offset, limit, isImportant, tag); + await remoteDataSource.getNews(page, pageSize, isImportant, tag); return Right(newsList); } on ServerException { return const Left(ServerFailure()); diff --git a/lib/domain/entities/news_item.dart b/lib/domain/entities/news_item.dart index 0c6d2c2c..2e85c215 100644 --- a/lib/domain/entities/news_item.dart +++ b/lib/domain/entities/news_item.dart @@ -1,13 +1,11 @@ import 'package:equatable/equatable.dart'; -import 'package:rtu_mirea_app/domain/entities/strapi_media.dart'; class NewsItem extends Equatable { final String title; final String text; final DateTime date; - final List images; + final List images; final List tags; - final bool isImportant; const NewsItem({ required this.title, @@ -15,9 +13,8 @@ class NewsItem extends Equatable { required this.date, required this.images, required this.tags, - required this.isImportant, }); @override - List get props => [title, text, date, images, tags, isImportant]; + List get props => [title, text, date, images, tags]; } diff --git a/lib/domain/repositories/news_repository.dart b/lib/domain/repositories/news_repository.dart index a26c58e3..44feaba6 100644 --- a/lib/domain/repositories/news_repository.dart +++ b/lib/domain/repositories/news_repository.dart @@ -4,6 +4,6 @@ import 'package:rtu_mirea_app/domain/entities/news_item.dart'; abstract class NewsRepository { Future>> getNews( - int offset, int limit, bool isImportant, String? tag); + int page, int pageSize, bool isImportant, String? tag); Future>> getTags(); } diff --git a/lib/domain/usecases/get_news.dart b/lib/domain/usecases/get_news.dart index 60789a82..b2e5cc47 100644 --- a/lib/domain/usecases/get_news.dart +++ b/lib/domain/usecases/get_news.dart @@ -13,23 +13,23 @@ class GetNews extends UseCase, GetNewsParams> { @override Future>> call(GetNewsParams params) async { return await newsRepository.getNews( - params.offset, params.limit, params.isImportant, params.tag); + params.page, params.pageSize, params.isImportant, params.tag); } } class GetNewsParams extends Equatable { - final int offset; - final int limit; + final int page; + final int pageSize; final bool isImportant; final String? tag; const GetNewsParams({ - required this.offset, - required this.limit, + required this.page, + required this.pageSize, required this.isImportant, this.tag, }); @override - List get props => [offset, limit, isImportant, tag]; + List get props => [page, pageSize, isImportant, tag]; } diff --git a/lib/presentation/bloc/news_bloc/news_bloc.dart b/lib/presentation/bloc/news_bloc/news_bloc.dart index bba0c77a..8158ce10 100644 --- a/lib/presentation/bloc/news_bloc/news_bloc.dart +++ b/lib/presentation/bloc/news_bloc/news_bloc.dart @@ -15,71 +15,74 @@ class NewsBloc extends Bloc { on(_onNewsLoadEvent); } + final pageSize = 10; + final GetNews getNews; final GetNewsTags getNewsTags; - bool _isFirstFetch = true; - int _offset = 0; - String? _selectedTag; + String? _getTagOrNull(String? tag) { + if (tag == null) return null; - void _onNewsLoadEvent(NewsLoadEvent event, Emitter emit) async { - if (state is NewsLoading) return; + if (tag == 'все') return null; - final bool refresh = event.refresh ?? false; - if (refresh) { - _isFirstFetch = true; - _offset = 0; - } + return tag; + } + + void _onNewsLoadEvent(NewsLoadEvent event, Emitter emit) async { + if (state is NewsLoaded) { + final st = state as NewsLoaded; - List tagsList = []; - List oldNews = []; + emit(NewsLoading(isFirstFetch: event.refresh == true)); - // True if the tag list failed to load - bool hasFetchError = false; + final newsEither = await getNews( + GetNewsParams( + page: event.refresh == true ? 1 : st.page + 1, + pageSize: pageSize, + isImportant: event.isImportant, + tag: _getTagOrNull(event.tag)), + ); - if (_isFirstFetch) { - emit(NewsLoading(oldNews: oldNews, isFirstFetch: true)); - _isFirstFetch = false; - final tags = await getNewsTags(); - tags.fold((failure) { - hasFetchError = true; - }, (r) { - tagsList = r; - }); + newsEither.fold( + (l) => emit(NewsLoadError()), + (r) { + emit(NewsLoaded( + news: event.refresh == true ? r : st.news + r, + tags: st.tags, + selectedTag: st.selectedTag, + page: st.page + 1, + )); + }, + ); } else { - if (state is NewsLoaded) { - tagsList = (state as NewsLoaded).tags; - oldNews = (state as NewsLoaded).news; - } - emit(NewsLoading(oldNews: oldNews, isFirstFetch: false)); - } + emit(NewsLoading(isFirstFetch: event.refresh == true)); - if (hasFetchError) { - emit(NewsLoadError()); - return; - } + final newsEither = await getNews( + GetNewsParams( + page: 1, + pageSize: pageSize, + isImportant: event.isImportant, + tag: _getTagOrNull(event.tag), + ), + ); - if (event.tag == "все") { - _selectedTag = null; - } else { - if ((event.tag != null)) { - if (_selectedTag == null || - (_selectedTag != null && event.tag != _selectedTag)) { - _selectedTag = event.tag; - } - } - } + final tagsEither = await getNewsTags(); - final news = await getNews(GetNewsParams( - offset: _offset, - limit: 10, - isImportant: event.isImportant, - tag: _selectedTag)); - emit(news.fold((failure) => NewsLoadError(), (r) { - List newNews = List.from(oldNews)..addAll(r); - _offset += r.length; - return NewsLoaded( - news: newNews, tags: tagsList, selectedTag: _selectedTag); - })); + newsEither.fold( + (l) => emit(NewsLoadError()), + (r) { + tagsEither.fold( + (l) => emit(NewsLoadError()), + (tags) { + emit(NewsLoaded( + news: r, + tags: tags, + selectedTag: event.tag, + page: 1, + )); + }, + ); + }, + ); + } } } diff --git a/lib/presentation/bloc/news_bloc/news_state.dart b/lib/presentation/bloc/news_bloc/news_state.dart index 32673d45..e248bfb7 100644 --- a/lib/presentation/bloc/news_bloc/news_state.dart +++ b/lib/presentation/bloc/news_bloc/news_state.dart @@ -11,12 +11,11 @@ class NewsInitial extends NewsState {} class NewsLoading extends NewsState { final bool isFirstFetch; - final List oldNews; - const NewsLoading({required this.isFirstFetch, required this.oldNews}); + const NewsLoading({required this.isFirstFetch}); @override - List get props => [isFirstFetch, oldNews]; + List get props => [isFirstFetch]; } class NewsLoaded extends NewsState { @@ -24,10 +23,17 @@ class NewsLoaded extends NewsState { final List tags; final String? selectedTag; - const NewsLoaded({required this.news, required this.tags, this.selectedTag}); + final int page; + + const NewsLoaded({ + required this.news, + required this.tags, + this.selectedTag, + required this.page, + }); @override - List get props => [news, tags]; + List get props => [news, tags, page]; } class NewsLoadError extends NewsState {} diff --git a/lib/presentation/pages/news/news_details_page.dart b/lib/presentation/pages/news/news_details_page.dart index ff5d286b..a22c3e1e 100644 --- a/lib/presentation/pages/news/news_details_page.dart +++ b/lib/presentation/pages/news/news_details_page.dart @@ -3,7 +3,6 @@ import 'package:flutter_html/flutter_html.dart'; import 'package:flutter_html_iframe/flutter_html_iframe.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:intl/intl.dart'; -import 'package:rtu_mirea_app/common/utils/strapi_utils.dart'; import 'package:rtu_mirea_app/domain/entities/news_item.dart'; import 'package:rtu_mirea_app/presentation/pages/news/widgets/tag_badge.dart'; import 'package:rtu_mirea_app/presentation/widgets/images_horizontal_slider.dart'; @@ -29,10 +28,7 @@ class NewsDetailsPage extends StatelessWidget { children: [ Positioned.fill( child: Image.network( - newsItem.images[0].formats != null - ? StrapiUtils.getMediumImageUrl( - newsItem.images[0].formats!) - : newsItem.images[0].url, + newsItem.images[0], fit: BoxFit.cover, ), ), diff --git a/lib/presentation/pages/news/news_page.dart b/lib/presentation/pages/news/news_page.dart index 1831afeb..caffad7a 100644 --- a/lib/presentation/pages/news/news_page.dart +++ b/lib/presentation/pages/news/news_page.dart @@ -3,11 +3,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:rtu_mirea_app/domain/entities/news_item.dart'; import 'package:rtu_mirea_app/presentation/bloc/news_bloc/news_bloc.dart'; -import 'package:rtu_mirea_app/presentation/bloc/stories_bloc/stories_bloc.dart'; import 'package:rtu_mirea_app/presentation/widgets/buttons/app_settings_button.dart'; import 'package:rtu_mirea_app/presentation/widgets/buttons/primary_tab_button.dart'; import 'package:shimmer/shimmer.dart'; -import 'widgets/news_item.dart'; +import 'widgets/news_card.dart'; import 'widgets/tag_badge.dart'; import 'package:rtu_mirea_app/presentation/typography.dart'; import 'package:rtu_mirea_app/presentation/theme.dart'; @@ -20,7 +19,30 @@ class NewsPage extends StatefulWidget { } class _NewsPageState extends State { - final _scrollController = ScrollController(); + late final ScrollController _scrollController; + + @override + void initState() { + super.initState(); + _scrollController = ScrollController()..addListener(_scrollListener); + } + + @override + void dispose() { + _scrollController.removeListener(_scrollListener); + super.dispose(); + } + + void _scrollListener() { + if (_scrollController.position.pixels >= + _scrollController.position.maxScrollExtent - 200) { + if (context.read().state is! NewsLoading) { + context.read().add(NewsLoadEvent( + isImportant: _tabValueNotifier.value == 1, + )); + } + } + } final ValueNotifier _tabValueNotifier = ValueNotifier(0); @@ -179,61 +201,39 @@ class _NewsPageState extends State { appBar: AppBar( title: const Text("Новости"), ), - body: NestedScrollView( - controller: _scrollController, - headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { - return [ - const SliverAppBar( - automaticallyImplyLeading: false, - toolbarHeight: 0, - elevation: 0, - primary: false, - actionsIconTheme: IconThemeData(opacity: 0.0), - ), - ]; - }, - body: Builder( - builder: (BuildContext context) { - final innerScrollController = PrimaryScrollController.of(context); - _setupScrollController(innerScrollController); + body: Builder( + builder: (BuildContext context) { + List news = []; + bool isLoading = false; - return RefreshIndicator( - onRefresh: () async { - context.read().add(NewsLoadEvent( - refresh: true, isImportant: _tabValueNotifier.value == 1)); - context.read().add(LoadStories()); - }, - child: Column(children: [ - const SizedBox(height: 16), - _buildTabButtons(context), - BlocBuilder( + return Column( + children: [ + const SizedBox(height: 16), + _buildTabButtons(context), + Expanded( + child: BlocBuilder( builder: (context, state) { - List news = []; - bool isLoading = false; - if (state is NewsInitial) { context.read().add(NewsLoadEvent( - isImportant: _tabValueNotifier.value == 1)); + isImportant: _tabValueNotifier.value == 1, + refresh: true)); } else if (state is NewsLoaded) { news = state.news; } else if (state is NewsLoading && state.isFirstFetch) { - return Expanded( - child: Column( - children: [ - const SizedBox(height: 12), - Expanded( - child: ListView.builder( - physics: const NeverScrollableScrollPhysics(), - itemCount: 3, - itemBuilder: (context, index) => - const _ShimmerNewsCardLoading(), - ), + return Column( + children: [ + const SizedBox(height: 12), + Expanded( + child: ListView.builder( + physics: const NeverScrollableScrollPhysics(), + itemCount: 3, + itemBuilder: (context, index) => + const _ShimmerNewsCardLoading(), ), - ], - ), + ), + ], ); } else if (state is NewsLoading) { - news = state.oldNews; isLoading = true; } else if (state is NewsLoadError) { return SingleChildScrollView( @@ -247,60 +247,42 @@ class _NewsPageState extends State { ), ); } - return Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + return SingleChildScrollView( + controller: _scrollController, + child: Wrap( + alignment: WrapAlignment.start, + spacing: 0, + runSpacing: 0, children: [ - const SizedBox(height: 12), - Expanded( - child: SingleChildScrollView( - child: Wrap( - alignment: WrapAlignment.start, - spacing: 0, - runSpacing: 0, - children: [ - for (var index = 0; - index < news.length; - index++) - SizedBox( - width: _computeWidth(context), - child: NewsItemWidget( - newsItem: news[index], - onClickNewsTag: (tag) => - _filterNewsByTag( - context.read(), tag), - ), - ), - if (isLoading) - const Center( - child: CircularProgressIndicator(), - ), - ], + const SizedBox( + width: double.infinity, + height: 16, + ), + for (var index = 0; index < news.length; index++) + SizedBox( + width: _computeWidth(context), + child: NewsCard( + newsItem: news[index], + onClickNewsTag: (tag) => _filterNewsByTag( + context.read(), tag), ), ), - ), + if (isLoading) + const Center( + child: CircularProgressIndicator(), + ), ], ), ); }, ), - ]), - ); - }, - ), + ), + ], + ); + }, ), ); } - - void _setupScrollController(ScrollController controller) { - controller.addListener(() { - if (controller.position.pixels == controller.position.maxScrollExtent) { - context - .read() - .add(NewsLoadEvent(isImportant: _tabValueNotifier.value == 1)); - } - }); - } } /// Widget with news card loading animation (shimmer effect). diff --git a/lib/presentation/pages/news/widgets/news_item.dart b/lib/presentation/pages/news/widgets/news_card.dart similarity index 89% rename from lib/presentation/pages/news/widgets/news_item.dart rename to lib/presentation/pages/news/widgets/news_card.dart index 1a8a7040..66ae84b6 100644 --- a/lib/presentation/pages/news/widgets/news_item.dart +++ b/lib/presentation/pages/news/widgets/news_card.dart @@ -2,7 +2,6 @@ import 'package:auto_route/auto_route.dart'; import 'package:extended_image/extended_image.dart'; import 'package:firebase_analytics/firebase_analytics.dart'; import 'package:flutter/material.dart'; -import 'package:rtu_mirea_app/common/utils/strapi_utils.dart'; import 'package:rtu_mirea_app/domain/entities/news_item.dart'; import 'package:intl/intl.dart'; import 'package:rtu_mirea_app/presentation/core/routes/routes.gr.dart'; @@ -11,13 +10,23 @@ import 'package:rtu_mirea_app/presentation/theme.dart'; import 'package:shimmer/shimmer.dart'; import 'package:rtu_mirea_app/presentation/typography.dart'; -class NewsItemWidget extends StatelessWidget { +class NewsCard extends StatelessWidget { final NewsItem newsItem; final Function(String)? onClickNewsTag; - const NewsItemWidget({Key? key, required this.newsItem, this.onClickNewsTag}) + const NewsCard({Key? key, required this.newsItem, this.onClickNewsTag}) : super(key: key); + bool isTagsNotEmpty() { + if (newsItem.tags.isEmpty) { + return false; + } else if (newsItem.tags.length == 1 && newsItem.tags[0].isEmpty) { + return false; + } + + return true; + } + @override Widget build(BuildContext context) { return GestureDetector( @@ -42,9 +51,7 @@ class NewsItemWidget extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ ExtendedImage.network( - newsItem.images[0].formats != null - ? StrapiUtils.getMediumImageUrl(newsItem.images[0].formats!) - : newsItem.images[0].url, + newsItem.images[0], height: 175, width: MediaQuery.of(context).size.width, fit: BoxFit.cover, @@ -116,13 +123,13 @@ class NewsItemWidget extends StatelessWidget { textAlign: TextAlign.start, style: AppTextStyle.captionL .copyWith(color: AppTheme.colors.secondary)), - newsItem.tags.isNotEmpty - ? const SizedBox(height: 16) + isTagsNotEmpty() ? const SizedBox(height: 16) : Container(), + isTagsNotEmpty() + ? _Tags( + tags: newsItem.tags, + onClick: onClickNewsTag, + ) : Container(), - _Tags( - tags: newsItem.tags, - onClick: onClickNewsTag, - ), ], ), ), diff --git a/lib/presentation/pages/profile/profile_announces_page.dart b/lib/presentation/pages/profile/profile_announces_page.dart index 1fda002e..74417dd3 100644 --- a/lib/presentation/pages/profile/profile_announces_page.dart +++ b/lib/presentation/pages/profile/profile_announces_page.dart @@ -57,7 +57,7 @@ class ProfileAnnouncesPage extends StatelessWidget { "body": Style( fontStyle: AppTextStyle.bodyRegular.fontStyle, fontWeight: AppTextStyle.bodyRegular.fontWeight, - padding: const EdgeInsets.all(0), + padding: HtmlPaddings.all(0), margin: Margins.all(0), ), }, diff --git a/lib/presentation/pages/profile/profile_nfc_pass_page.dart b/lib/presentation/pages/profile/profile_nfc_pass_page.dart index 653b68d1..025af550 100644 --- a/lib/presentation/pages/profile/profile_nfc_pass_page.dart +++ b/lib/presentation/pages/profile/profile_nfc_pass_page.dart @@ -690,7 +690,7 @@ class _NfcNotAviable extends StatelessWidget { TextOutlinedButton( content: "Включить NFC", onPressed: () { - AppSettings.openNFCSettings(); + AppSettings.openAppSettings(type: AppSettingsType.nfc); }, ), ], diff --git a/lib/presentation/pages/schedule/widgets/stories_wrapper.dart b/lib/presentation/pages/schedule/widgets/stories_wrapper.dart index 7c37479d..fdd5c8ee 100644 --- a/lib/presentation/pages/schedule/widgets/stories_wrapper.dart +++ b/lib/presentation/pages/schedule/widgets/stories_wrapper.dart @@ -3,9 +3,9 @@ import 'package:dismissible_page/dismissible_page.dart'; import 'package:firebase_analytics/firebase_analytics.dart'; import 'package:flutter/material.dart'; import 'package:rtu_mirea_app/common/utils/utils.dart'; -import 'package:story/story_page_view/story_page_view.dart'; import 'package:rtu_mirea_app/domain/entities/story.dart'; import 'package:rtu_mirea_app/presentation/widgets/buttons/primary_button.dart'; +import 'package:story/story.dart'; import 'package:url_launcher/url_launcher_string.dart'; import 'package:rtu_mirea_app/presentation/typography.dart'; diff --git a/lib/presentation/widgets/images_horizontal_slider.dart b/lib/presentation/widgets/images_horizontal_slider.dart index e62c1815..361c2180 100644 --- a/lib/presentation/widgets/images_horizontal_slider.dart +++ b/lib/presentation/widgets/images_horizontal_slider.dart @@ -1,6 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:rtu_mirea_app/common/utils/utils.dart'; -import 'package:rtu_mirea_app/domain/entities/strapi_media.dart'; import 'fullscreen_image.dart'; @@ -8,7 +6,7 @@ class ImagesHorizontalSlider extends StatelessWidget { const ImagesHorizontalSlider({Key? key, required this.images}) : super(key: key); - final List images; + final List images; @override Widget build(BuildContext context) { @@ -26,10 +24,7 @@ class ImagesHorizontalSlider extends StatelessWidget { context, MaterialPageRoute( builder: (_) => FullScreenImage( - imageUrl: images[index].formats != null - ? StrapiUtils.getLargestImageUrl( - images[index].formats!) - : images[index].url, + imageUrl: images[index], ), ), ); @@ -39,9 +34,7 @@ class ImagesHorizontalSlider extends StatelessWidget { child: ClipRRect( borderRadius: BorderRadius.circular(12.0), child: Image.network( - images[index].formats != null - ? images[index].formats!.thumbnail.url - : images[index].url, + images[index], height: 112, width: 158, fit: BoxFit.cover, diff --git a/linux/flutter/ephemeral/.plugin_symlinks/connectivity_plus b/linux/flutter/ephemeral/.plugin_symlinks/connectivity_plus index af28af46..2de1745a 120000 --- a/linux/flutter/ephemeral/.plugin_symlinks/connectivity_plus +++ b/linux/flutter/ephemeral/.plugin_symlinks/connectivity_plus @@ -1 +1 @@ -C:/Users/foran/AppData/Local/Pub/Cache/hosted/pub.dev/connectivity_plus-4.0.0/ \ No newline at end of file +C:/Users/foran/AppData/Local/Pub/Cache/hosted/pub.dev/connectivity_plus-4.0.2/ \ No newline at end of file diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus index 5ab93d7b..29bebb80 120000 --- a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus @@ -1 +1 @@ -C:/Users/foran/AppData/Local/Pub/Cache/hosted/pub.dev/device_info_plus-9.0.0/ \ No newline at end of file +C:/Users/foran/AppData/Local/Pub/Cache/hosted/pub.dev/device_info_plus-9.0.3/ \ No newline at end of file diff --git a/linux/flutter/ephemeral/.plugin_symlinks/flutter_secure_storage_linux b/linux/flutter/ephemeral/.plugin_symlinks/flutter_secure_storage_linux index b4c4aae2..c9e97b07 120000 --- a/linux/flutter/ephemeral/.plugin_symlinks/flutter_secure_storage_linux +++ b/linux/flutter/ephemeral/.plugin_symlinks/flutter_secure_storage_linux @@ -1 +1 @@ -C:/Users/foran/AppData/Local/Pub/Cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.3/ \ No newline at end of file +C:/Users/foran/AppData/Local/Pub/Cache/hosted/pub.dev/flutter_secure_storage_linux-1.2.0/ \ No newline at end of file diff --git a/linux/flutter/ephemeral/.plugin_symlinks/flutter_web_auth_2 b/linux/flutter/ephemeral/.plugin_symlinks/flutter_web_auth_2 index 66c1a0c3..ed6719dc 120000 --- a/linux/flutter/ephemeral/.plugin_symlinks/flutter_web_auth_2 +++ b/linux/flutter/ephemeral/.plugin_symlinks/flutter_web_auth_2 @@ -1 +1 @@ -C:/Users/foran/AppData/Local/Pub/Cache/hosted/pub.dev/flutter_web_auth_2-2.1.4/ \ No newline at end of file +C:/Users/foran/AppData/Local/Pub/Cache/hosted/pub.dev/flutter_web_auth_2-2.2.1/ \ No newline at end of file diff --git a/linux/flutter/ephemeral/.plugin_symlinks/package_info_plus b/linux/flutter/ephemeral/.plugin_symlinks/package_info_plus index 4fe4e02d..73c632c7 120000 --- a/linux/flutter/ephemeral/.plugin_symlinks/package_info_plus +++ b/linux/flutter/ephemeral/.plugin_symlinks/package_info_plus @@ -1 +1 @@ -C:/Users/foran/AppData/Local/Pub/Cache/hosted/pub.dev/package_info_plus-3.1.2/ \ No newline at end of file +C:/Users/foran/AppData/Local/Pub/Cache/hosted/pub.dev/package_info_plus-4.1.0/ \ No newline at end of file diff --git a/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux index 8b234d5f..fdd4fd67 120000 --- a/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux +++ b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux @@ -1 +1 @@ -C:/Users/foran/AppData/Local/Pub/Cache/hosted/pub.dev/path_provider_linux-2.1.10/ \ No newline at end of file +C:/Users/foran/AppData/Local/Pub/Cache/hosted/pub.dev/path_provider_linux-2.2.1/ \ No newline at end of file diff --git a/linux/flutter/ephemeral/.plugin_symlinks/sentry_flutter b/linux/flutter/ephemeral/.plugin_symlinks/sentry_flutter index 6affc845..cf1c37e2 120000 --- a/linux/flutter/ephemeral/.plugin_symlinks/sentry_flutter +++ b/linux/flutter/ephemeral/.plugin_symlinks/sentry_flutter @@ -1 +1 @@ -C:/Users/foran/AppData/Local/Pub/Cache/hosted/pub.dev/sentry_flutter-7.6.1/ \ No newline at end of file +C:/Users/foran/AppData/Local/Pub/Cache/hosted/pub.dev/sentry_flutter-7.9.0/ \ No newline at end of file diff --git a/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux index 48f04bfe..799d2673 120000 --- a/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux +++ b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux @@ -1 +1 @@ -C:/Users/foran/AppData/Local/Pub/Cache/hosted/pub.dev/shared_preferences_linux-2.2.0/ \ No newline at end of file +C:/Users/foran/AppData/Local/Pub/Cache/hosted/pub.dev/shared_preferences_linux-2.3.1/ \ No newline at end of file diff --git a/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux index ca759c22..46c954e5 120000 --- a/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux +++ b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux @@ -1 +1 @@ -C:/Users/foran/AppData/Local/Pub/Cache/hosted/pub.dev/url_launcher_linux-3.0.5/ \ No newline at end of file +C:/Users/foran/AppData/Local/Pub/Cache/hosted/pub.dev/url_launcher_linux-3.0.6/ \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 1e86b653..f8d0ec11 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -12,10 +12,10 @@ publish_to: 'none' # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.3.4+28 +version: 1.3.5+29 environment: - sdk: ">=2.19.0 <3.0.0" + sdk: ">=3.1.1" dependencies: flutter: @@ -87,15 +87,15 @@ dependencies: # dates or a range of dates. It has four built-in views that allow quick # navigation to the desired date. # See https://pub.dev/packages/syncfusion_flutter_datepicker - syncfusion_flutter_datepicker: ^21.2.4 + syncfusion_flutter_datepicker: ^22.2.12 # A Flutter widget rendering static HTML and CSS as Flutter widgets. # See https://pub.dev/packages/flutter_html - flutter_html: ^3.0.0-beta.1 + flutter_html: ^3.0.0-beta.2 # Iframe widget for flutter_html # See https://pub.dev/packages/flutter_html_iframe - flutter_html_iframe: ^3.0.0-beta.1 + flutter_html_iframe: ^3.0.0-beta.2 # The Font Awesome Icon pack available as Flutter Icons. # Provides 1600 additional icons to use in your apps. @@ -113,29 +113,26 @@ dependencies: # Instagram stories like UI with rich animations and customizability. # See https://pub.dev/packages/story - story: - git: - url: https://github.com/0niel/story.git - ref: main + story: ^1.1.0 # Official extension image, support placeholder(loading)/ failed state, # cache network, zoom/pan, photo view, slide out page, # editor(crop,rotate,flip), painting etc. - extended_image: ^8.0.1 + extended_image: ^8.1.0 # A package provides an easy way to add shimmer effect in Flutter project # See https://pub.dev/packages/shimmer - shimmer: ^2.0.0 + shimmer: ^3.0.0 # Load and cache network images with with placeholder and error widgets. # See https://pub.dev/packages/cached_network_image cached_network_image: ^3.2.0 - syncfusion_flutter_datagrid: ^21.2.4 - syncfusion_flutter_core: ^21.2.4 - syncfusion_flutter_sliders: ^21.2.4 - syncfusion_flutter_charts: ^21.2.4 - syncfusion_flutter_gauges: ^21.2.4 + syncfusion_flutter_datagrid: ^22.2.12 + syncfusion_flutter_core: ^22.2.12 + syncfusion_flutter_sliders: ^22.2.12 + syncfusion_flutter_charts: ^22.2.12 + syncfusion_flutter_gauges: ^22.2.12 auto_route: ^5.0.4 @@ -149,7 +146,7 @@ dependencies: # Get version name in runtime # https://pub.dev/packages/package_info_plus - package_info_plus: ^3.0.2 + package_info_plus: ^4.1.0 # Encapsulates the notion of the "current time". Very useful for testing # See https://pub.dev/packages/clock @@ -165,7 +162,7 @@ dependencies: get_storage: # https://pub.dev/packages/home_widget - home_widget: ^0.2.0+1 + home_widget: ^0.3.0 freezed_annotation: ^2.1.0 @@ -191,11 +188,11 @@ dependencies: # A Flutter plugin for opening iOS and Android phone settings from an app. # See https://pub.dev/packages/app_settings - app_settings: ^4.2.0 + app_settings: ^5.0.0 - sentry_flutter: ^7.6.3 - sentry_dio: ^7.6.3 - sentry_logging: ^7.6.3 + sentry_flutter: ^7.9.0 + sentry_dio: ^7.9.0 + sentry_logging: ^7.9.0 logging: ^1.1.1 # 1000+ beautiful icons to use in you dream project, with all the customization Flutter @@ -216,6 +213,7 @@ dev_dependencies: flutter_launcher_icons: ^0.13.1 auto_route_generator: ^5.0.3 build_runner: + # https://pub.dev/packages/freezed freezed: ^2.1.0+1 json_serializable: