Merge pull request 'main' (#34) from eatvio/eatvio_app:main into main

Reviewed-on: maxxkim/eatvio_app#34
This commit is contained in:
2024-06-24 14:46:43 +00:00
7 changed files with 91 additions and 547 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -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"

View File

@@ -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 }}

104
bpc
View File

@@ -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<BlogPostCreateBloc>(
create: (context) => BlogPostCreateBloc(BlogPostCreateState(
blog_postModelObj:
BlogPostCreateModel(blog_postID: blog_postID.toString())))
..add(BlogPostCreateInitialEvent()),
child: BlogPostCreateScreen());
}
Widget build(BuildContext context) {
return BlocBuilder<BlogPostCreateBloc, BlogPostCreateState>(
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<BlogPostCreateBloc>()
.add(CreateBlogPost()),
child: Text('Создать'),
)
]),
)
]),
),
),
bottomNavigationBar: _buildBottomBar(context));
}
}
_buildBottomBar(BuildContext context) {
return CustomBottomBar(onChanged: (BottomBarEnum type) {});
}

313
fc
View File

@@ -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<FeedBloc>(
create: (context) => FeedBloc(FeedState(myProfileModelObj: FeedModel()))
..add(FeedInitialEvent()),
child: FeedScreen());
}
Widget build(BuildContext context) {
return BlocBuilder<FeedBloc, FeedState>(
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<Widget> 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<String>(
onSelected: (value) => print("tap"),
itemBuilder: (BuildContext context) => <PopupMenuEntry<String>>[
PopupMenuItem<String>(
value: 'edit',
child: Text('Редактировать'),
),
PopupMenuItem<String>(
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: <Widget>[
ScrollItem(title: 'Все'),
ScrollItem(title: 'Рецепты'),
ScrollItem(title: 'Диеты'),
ScrollItem(title: 'Планы'),
ScrollItem(title: 'Записи'),
],
),
),
);
}
}

View File

@@ -45,6 +45,7 @@ class ChatSelectScreen extends StatelessWidget {
return [
SliverAppBar(
backgroundColor: Colors.white,
stretchTriggerOffset: 1,
forceMaterialTransparency: true,
floating: true,
snap: true,

102
rc
View File

@@ -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<RecipeCreateBloc>(
create: (context) => RecipeCreateBloc(RecipeCreateState(
recipeModelObj: RecipeCreateModel(recipeID: recipeID.toString())))
..add(RecipeCreateInitialEvent()),
child: RecipeCreateScreen());
}
Widget build(BuildContext context) {
return BlocBuilder<RecipeCreateBloc, RecipeCreateState>(
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<RecipeCreateBloc>().add(CreateRecipe()),
child: Text('Создать'),
)
]),
)
]),
),
),
bottomNavigationBar: _buildBottomBar(context));
}
}
_buildBottomBar(BuildContext context) {
return CustomBottomBar(onChanged: (BottomBarEnum type) {});
}