diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 506ab56a..00000000 Binary files a/.DS_Store and /dev/null differ diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index 4a2d90f8..955d74d5 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -1,6 +1,6 @@ name: Android Release -on: [push, pull_request] +on: [ push, pull_request ] env: flutter_version: "3.22.0" @@ -13,22 +13,37 @@ jobs: steps: - uses: actions/checkout@v3 + + - name: Set up JDK + uses: actions/setup-java@v3 + with: + distribution: 'zulu' + java-version: ${{ env.java_version }} + cache: 'gradle' + + - name: Install Android SDK + run: | + apt-get update + apt-get install -y openjdk-11-jdk wget + wget https://dl.google.com/android/repository/commandlinetools-linux-7583922_latest.zip -O commandlinetools.zip + unzip commandlinetools.zip + mkdir -p $HOME/Android/Sdk/cmdline-tools/latest + mv cmdline-tools/* $HOME/Android/Sdk/cmdline-tools/latest/ + export ANDROID_SDK_ROOT=$HOME/Android/Sdk + export PATH=$PATH:$HOME/Android/Sdk/cmdline-tools/latest/bin + sdkmanager "platform-tools" "platforms;android-30" "build-tools;30.0.3" + + - name: Set up Android environment variables + run: | + echo "ANDROID_SDK_ROOT=$HOME/Android/Sdk" >> $GITHUB_ENV + echo "PATH=$PATH:$HOME/Android/Sdk/platform-tools:$HOME/Android/Sdk/build-tools/30.0.3" >> $GITHUB_ENV + echo "ANDROID_HOME=$HOME/Android/Sdk" >> $GITHUB_ENV + - uses: actions/cache@v2 with: path: ${{ runner.tool_cache }}/flutter key: flutter-${{ env.flutter_version }}-${{ env.flutter_channel }} - - name: Install jq - run: | - apt update - apt-get install -y jq - - - uses: actions/setup-java@v3 - with: - distribution: "zulu" - java-version: "12.x" - cache: "gradle" - - id: flutter-action uses: actions/flutter-action@v2 with: @@ -66,9 +81,12 @@ jobs: touch .env flutter test -# - name: Build apk -# run: flutter build apk + - name: Build apk + run: flutter build apk -# Runs a set of commands using the runners shell -# - name: Start release build -# run: flutter build appbundle + - name: Rename and move apk + run: | + TIMESTAMP=$(date +'%Y-%m-%d-%H-%M') + APK_NAME="eatvio_app_${TIMESTAMP}.apk" + mv build/app/outputs/flutter-apk/app-release.apk $APK_NAME + echo "APK build finished $APK_NAME" diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index 27c7c439..ffd32815 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -1,6 +1,6 @@ name: Eatvio App Android Test -on: [pull_request] +on: [ pull_request ] env: flutter_version: "3.22.0" @@ -13,6 +13,38 @@ jobs: steps: - uses: actions/checkout@v3 + + - name: Set up JDK + uses: actions/setup-java@v3 + with: + distribution: "zulu" + java-version: ${{ env.java_version }} + cache: "gradle" + + - name: Install Android SDK + run: | + apt-get update + apt-get install -y openjdk-11-jdk wget + wget https://dl.google.com/android/repository/commandlinetools-linux-7583922_latest.zip -O commandlinetools.zip + unzip commandlinetools.zip + mkdir -p $HOME/Android/Sdk/cmdline-tools/latest + mv cmdline-tools/* $HOME/Android/Sdk/cmdline-tools/latest/ + export ANDROID_SDK_ROOT=$HOME/Android/Sdk + export PATH=$PATH:$HOME/Android/Sdk/cmdline-tools/latest/bin + yes | sdkmanager --licenses 2>/dev/null || true + + - name: Set up Android environment variables + run: | + echo "ANDROID_SDK_ROOT=$HOME/Android/Sdk" >> $GITHUB_ENV + echo "PATH=$PATH:$HOME/Android/Sdk/cmdline-tools/latest/bin:$HOME/Android/Sdk/platform-tools:$HOME/Android/Sdk/build-tools/30.0.3" >> $GITHUB_ENV + echo "ANDROID_HOME=$HOME/Android/Sdk" >> $GITHUB_ENV + + - name: Debug Environment Variables + run: | + echo "ANDROID_SDK_ROOT: $ANDROID_SDK_ROOT" + echo "ANDROID_HOME: $ANDROID_HOME" + echo "PATH: $PATH" + - uses: actions/cache@v2 with: path: ${{ runner.tool_cache }}/flutter @@ -20,15 +52,8 @@ jobs: - name: Install jq run: | - apt update apt-get install -y jq - - uses: actions/setup-java@v3 - with: - distribution: "zulu" - java-version: "12.x" - cache: "gradle" - - id: flutter-action uses: actions/flutter-action@v2 with: @@ -36,7 +61,7 @@ jobs: flutter-version: ${{ env.flutter_version }} cache: true - - name: show cache keys + - name: Show cache keys run: | echo CACHE-PATH=${{ steps.flutter-action.outputs.CACHE-PATH }} echo CACHE-KEY=${{ steps.flutter-action.outputs.CACHE-KEY }} @@ -47,10 +72,11 @@ jobs: echo PUB-CACHE-KEY=${{ steps.flutter-action.outputs.PUB-CACHE-KEY }} shell: bash - - name: fix dir permissions + - name: Fix dir permissions run: | git config --global --add safe.directory /opt/hostedtoolcache/flutter/${{ env.flutter_channel }}-${{ env.flutter_version }}-${{ steps.flutter-action.outputs.ARCHITECTURE }} - flutter --version + flutter config --android-sdk="$ANDROID_HOME" + flutter doctor -v - name: Get dependencies run: flutter pub get @@ -65,3 +91,21 @@ jobs: run: | touch .env flutter test + + - name: Build apk + run: | + flutter build apk + + - name: Rename and move apk + run: | + TIMESTAMP=$(date +'%Y-%m-%d-%H-%M') + APK_NAME="eatvio_app_${TIMESTAMP}.apk" + mv build/app/outputs/flutter-apk/app-release.apk $APK_NAME + echo "APK build finished $APK_NAME" + echo "APK_NAME=$APK_NAME" >> $GITHUB_ENV + + - name: Upload APK artifact + uses: actions/upload-artifact@v3 + with: + name: ${{ env.APK_NAME }} + path: ${{ env.APK_NAME }} diff --git a/bpc b/bpc deleted file mode 100644 index 7221be5e..00000000 --- a/bpc +++ /dev/null @@ -1,104 +0,0 @@ -import 'bloc/blog_post_create_bloc.dart'; -import 'models/blog_post_create_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:flutter/material.dart'; -import 'package:eatvio_app/widgets/custom_bottom_bar.dart'; - -class BlogPostCreateScreen extends StatelessWidget { - const BlogPostCreateScreen({Key? key}) : super(key: key); - static Widget builder(BuildContext context) { - final blog_postID = ModalRoute.of(context)!.settings.arguments; - return BlocProvider( - create: (context) => BlogPostCreateBloc(BlogPostCreateState( - blog_postModelObj: - BlogPostCreateModel(blog_postID: blog_postID.toString()))) - ..add(BlogPostCreateInitialEvent()), - child: BlogPostCreateScreen()); - } - - Widget build(BuildContext context) { - return BlocBuilder( - builder: (context, state) { - if (state is BlogPostCreateInitialState) { - // Это начальное состояние, данные ещё не загружены. - return Container( - color: Colors.white, - ); - } else if (state is BlogPostCreateLoadedState) { - // Данные загружены, можно строить экран. - return _buildBlogPostCreate(context, state); - } else if (state is BlogPostCreateErrorState) { - // Произошла ошибка при загрузке данных. - return Center(child: Text(state.errorMessage)); - } else { - // Другие состояния, если они есть. - return Container(); // Пустой контейнер для необработанных состояний. - } - }, - ); - } - - _buildBlogPostCreate(BuildContext context, BlogPostCreateLoadedState state) { - mediaQueryData = MediaQuery.of(context); - return Scaffold( - resizeToAvoidBottomInset: false, - body: SafeArea( - child: Container( - width: double.maxFinite, - decoration: AppDecoration.fillGray, - child: ListView(children: [ - Container( - margin: EdgeInsets.only( - left: 16.h, - right: 20.h, - bottom: 10.h, - ), - padding: EdgeInsets.all(12.h), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.all(Radius.circular(12)), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 2, - blurRadius: 5, - offset: Offset(0, 3), - ), - ], - ), - child: Column(mainAxisSize: MainAxisSize.min, children: [ - SizedBox(height: 16.0), - TextFormField( - controller: state.title, - decoration: InputDecoration(labelText: 'Заголовок'), - ), - SizedBox(height: 16.0), - TextFormField( - controller: state.description, - decoration: InputDecoration(labelText: 'Описание'), - ), - SizedBox(height: 16.0), - TextFormField( - controller: state.youtube_url, - decoration: InputDecoration(labelText: 'Ссылка'), - ), - SizedBox(height: 16.0), - // Здесь нужно добавить виджет для загрузки картинки - ElevatedButton( - onPressed: () => context - .read() - .add(CreateBlogPost()), - child: Text('Создать'), - ) - ]), - ) - ]), - ), - ), - bottomNavigationBar: _buildBottomBar(context)); - } -} - -_buildBottomBar(BuildContext context) { - return CustomBottomBar(onChanged: (BottomBarEnum type) {}); -} diff --git a/fc b/fc deleted file mode 100644 index 07c67735..00000000 --- a/fc +++ /dev/null @@ -1,313 +0,0 @@ -import 'bloc/feed_bloc.dart'; -import 'models/feed_model.dart'; -import 'package:cached_network_image/cached_network_image.dart'; -import 'package:eatvio_app/presentation/feed/feed_screen/widgets/feed_search_view.dart'; -import 'package:eatvio_app/presentation/feed/feed_screen/widgets/feed_scroll_item.dart'; -import 'package:eatvio_app/widgets/custom_bottom_bar.dart'; -import 'package:eatvio_app/widgets/custom_outlined_button.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; -import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; - -class FeedScreen extends StatelessWidget { - static Widget builder(BuildContext context) { - return BlocProvider( - create: (context) => FeedBloc(FeedState(myProfileModelObj: FeedModel())) - ..add(FeedInitialEvent()), - child: FeedScreen()); - } - - Widget build(BuildContext context) { - return BlocBuilder( - builder: (context, state) { - if (state is FeedInitialState) { - // Это начальное состояние, данные ещё не загружены. - return CircularProgressIndicator( - color: Colors.white, - backgroundColor: Colors.white, - ); - } else if (state is FeedLoadedState) { - // Данные загружены, можно строить экран. - return _buildFeedScreen(context, state); - } else { - // Другие состояния, если они есть. - return Container(); // Пустой контейнер для необработанных состояний. - } - }, - ); - } - - _buildFeedScreen(BuildContext context, FeedLoadedState state) { - mediaQueryData = MediaQuery.of(context); - return Scaffold( - backgroundColor: Colors.grey[200], - resizeToAvoidBottomInset: true, - body: SafeArea( - child: SingleChildScrollView( - child: Container( - width: double.maxFinite, - decoration: BoxDecoration(color: Colors.grey[200]), - child: Padding( - padding: EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - _buildSearch(), - SizedBox(height: 20), - _buildMenu(context, state), - SizedBox(height: 20), - _buildBlogPostList(context, state) - ], - ), - ), - ), - ), - ), - bottomNavigationBar: _buildBottomBar(context), - ); - } - - _buildSearch() { - return Container( - margin: EdgeInsets.only(bottom: 10), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.all(Radius.circular(12)), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 2, - blurRadius: 5, - offset: Offset(0, 3), - ), - ], - ), - child: Padding( - padding: const EdgeInsets.all(12.0), - child: Column( - children: [ - CustomSearchView( - hintText: "Поиск записей", - ), - SizedBox(height: 10), - Row( - children: [ - Flexible( - flex: 5, - child: CustomOutlinedButton( - text: "Найти запись", - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - ), - ), - SizedBox(width: 8), // Add some spacing between the buttons - Flexible( - flex: 1, - child: CustomOutlinedButton( - text: "+", - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - ), - ), - ], - ) - ], - ), - ), - ); - } - - _buildBlogPostList(BuildContext context, FeedLoadedState state) { - List postWidgets = []; - - if (state.posts != null) { - for (var post in state.posts!) { - postWidgets.add(_buildFeedEntry(post, context)); - } - } - - return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: postWidgets, - ); - } - - _buildFeedEntry(post, BuildContext context) { - return Container( - margin: EdgeInsets.only(bottom: 10), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.all(Radius.circular(12)), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 2, - blurRadius: 5, - offset: Offset(0, 3), - ), - ], - ), - child: Column(children: [ - ListTile( - leading: CachedNetworkImage( - imageUrl: dotenv.env['STORAGE_URL']! + - (post["author"]['profile_photo_path'] ?? ''), - imageBuilder: (context, imageProvider) => CircleAvatar( - backgroundImage: imageProvider, - radius: 25, - ), - placeholder: (context, url) => CircularProgressIndicator(), - errorWidget: (context, url, error) => CircleAvatar( - child: Icon(Icons.person), - backgroundColor: Colors.white, - radius: 25, - ), - ), - title: Text( - post?['author']['name'] ?? '', - style: CustomTextStyles.titleMediumSemiBold, - ), - subtitle: Text( - DateFormat('dd.MM.yyyy') - .format(DateTime.parse(post?['post']['updated_at'])), - style: theme.textTheme.bodyMedium, - ), - onTap: () => Navigator.pushNamed( - context, - AppRoutes.blogPostScreen, - arguments: post?['post']['id'].toString(), - ), - trailing: PopupMenuButton( - onSelected: (value) => print("tap"), - itemBuilder: (BuildContext context) => >[ - PopupMenuItem( - value: 'edit', - child: Text('Редактировать'), - ), - PopupMenuItem( - value: 'delete', - child: Text('Удалить'), - ), - ], - ), - ), - Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Spacer(), - Align( - alignment: Alignment.center, - child: Text( - post?['post']['title'], - style: CustomTextStyles.titleMediumBlack, - ), - ), - Spacer(), - ], - ), - SizedBox(height: 8.0), - Text( - post?['post']['description'], - style: CustomTextStyles.bodyMediumBluegray800, - ), - SizedBox(height: 16.0), - CachedNetworkImage( - imageUrl: dotenv.env['STORAGE_URL']! + - (post?['post']['image'] ?? ''), - imageBuilder: (context, imageProvider) => Stack( - children: [ - ClipRRect( - borderRadius: - const BorderRadius.all(Radius.circular(8.0)), - child: Image( - image: imageProvider, - ), - ), - ], - ), - placeholder: (context, url) => CircularProgressIndicator(), - ), - SizedBox(height: 16.0), - Row(children: [ - Padding( - padding: EdgeInsets.only(left: 4), - child: Row(children: [ - Padding( - padding: EdgeInsets.only(right: 4), - child: Icon(Icons.comment_outlined), - ), - Text( - "Комментировать", - ) - ]), - ), - Spacer(), - Row(children: [ - Padding( - padding: const EdgeInsets.only(right: 4), - child: Icon(Icons.favorite_outline), - ), - Text( - "Нравится", - ) - ]), - Spacer(), - Padding( - padding: EdgeInsets.only(right: 4), - child: Icon(Icons.share_outlined), - ), - ]), - ], - ), - ), - ])); - } - - Function onTapBack(BuildContext context) { - return () { - onTapArrowLeft(context); - }; - } - - _buildBottomBar(BuildContext context) { - return CustomBottomBar(onChanged: (BottomBarEnum type) {}); - } - - onTapArrowLeft(BuildContext context) { - NavigatorService.goBack(); - } - - _buildMenu(BuildContext context, FeedLoadedState state) { - return Container( - padding: EdgeInsets.all(12), - margin: EdgeInsets.only(bottom: 10), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.all(Radius.circular(12)), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 2, - blurRadius: 5, - offset: Offset(0, 3), - ), - ], - ), - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Row( - children: [ - ScrollItem(title: 'Все'), - ScrollItem(title: 'Рецепты'), - ScrollItem(title: 'Диеты'), - ScrollItem(title: 'Планы'), - ScrollItem(title: 'Записи'), - ], - ), - ), - ); - } -} diff --git a/lib/features/chat/presentation/pages/chat_select_screen/chat_select_screen.dart b/lib/features/chat/presentation/pages/chat_select_screen/chat_select_screen.dart index a2068225..fe468f3b 100644 --- a/lib/features/chat/presentation/pages/chat_select_screen/chat_select_screen.dart +++ b/lib/features/chat/presentation/pages/chat_select_screen/chat_select_screen.dart @@ -45,6 +45,7 @@ class ChatSelectScreen extends StatelessWidget { return [ SliverAppBar( backgroundColor: Colors.white, + stretchTriggerOffset: 1, forceMaterialTransparency: true, floating: true, snap: true, diff --git a/rc b/rc deleted file mode 100644 index 49ddfaa0..00000000 --- a/rc +++ /dev/null @@ -1,102 +0,0 @@ -import 'bloc/recipe_create_bloc.dart'; -import 'models/recipe_create_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:flutter/material.dart'; -import 'package:eatvio_app/widgets/custom_bottom_bar.dart'; - -class RecipeCreateScreen extends StatelessWidget { - const RecipeCreateScreen({Key? key}) : super(key: key); - static Widget builder(BuildContext context) { - final recipeID = ModalRoute.of(context)!.settings.arguments; - return BlocProvider( - create: (context) => RecipeCreateBloc(RecipeCreateState( - recipeModelObj: RecipeCreateModel(recipeID: recipeID.toString()))) - ..add(RecipeCreateInitialEvent()), - child: RecipeCreateScreen()); - } - - Widget build(BuildContext context) { - return BlocBuilder( - builder: (context, state) { - if (state is RecipeCreateInitialState) { - // Это начальное состояние, данные ещё не загружены. - return Container( - color: Colors.white, - ); - } else if (state is RecipeCreateLoadedState) { - // Данные загружены, можно строить экран. - return _buildRecipeCreate(context, state); - } else if (state is RecipeCreateErrorState) { - // Произошла ошибка при загрузке данных. - return Center(child: Text(state.errorMessage)); - } else { - // Другие состояния, если они есть. - return Container(); // Пустой контейнер для необработанных состояний. - } - }, - ); - } - - _buildRecipeCreate(BuildContext context, RecipeCreateLoadedState state) { - mediaQueryData = MediaQuery.of(context); - return Scaffold( - resizeToAvoidBottomInset: false, - body: SafeArea( - child: Container( - width: double.maxFinite, - decoration: AppDecoration.fillGray, - child: ListView(children: [ - Container( - margin: EdgeInsets.only( - left: 16.h, - right: 20.h, - bottom: 10.h, - ), - padding: EdgeInsets.all(12.h), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.all(Radius.circular(12)), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 2, - blurRadius: 5, - offset: Offset(0, 3), - ), - ], - ), - child: Column(mainAxisSize: MainAxisSize.min, children: [ - SizedBox(height: 16.0), - TextFormField( - controller: state.title, - decoration: InputDecoration(labelText: 'Заголовок'), - ), - SizedBox(height: 16.0), - TextFormField( - controller: state.description, - decoration: InputDecoration(labelText: 'Описание'), - ), - SizedBox(height: 16.0), - TextFormField( - controller: state.video_url, - decoration: InputDecoration(labelText: 'Ссылка'), - ), - SizedBox(height: 16.0), - // Здесь нужно добавить виджет для загрузки картинки - ElevatedButton( - onPressed: () => - context.read().add(CreateRecipe()), - child: Text('Создать'), - ) - ]), - ) - ]), - ), - ), - bottomNavigationBar: _buildBottomBar(context)); - } -} - -_buildBottomBar(BuildContext context) { - return CustomBottomBar(onChanged: (BottomBarEnum type) {}); -}