Commit 00ba0ca4 authored by Erfan Jazeb Nikoo's avatar Erfan Jazeb Nikoo
Browse files

UI improvements

parent 4e84e16b
Pipeline #8664 passed with stages
in 4 minutes and 38 seconds
Showing with 376 additions and 270 deletions
+376 -270
......@@ -19,8 +19,6 @@ class AppColors {
final Color orange = const Color(0xffff9500);
final Color yellow = const Color(0xffffcc00);
final Color green = const Color(0xff34c759);
final Color brandGreen = Color(0xff15B599);
final Color brandYellow = Color(0xffFFB039);
final Color primary = const Color(0xffFE570F);
final Color accent = const Color(0xff007aff);
......@@ -40,10 +38,13 @@ class AppColors {
final Color brandViolet = Color(0xff4F56FE);
final Color brandBlueText = const Color(0xff17a4e0);
final Color brandGreyText = const Color(0xff999999);
final Color brandGrey = const Color(0xff989898);
final Color brandWhite = const Color(0xfff5f5f5);
final Color brandBlack = const Color(0xff333333);
final Color brandOrange = const Color(0xffE9500F);
final Color brandLineGrey = const Color(0xfff0f0f0);
final Color brandGreen = Color(0xff15B599);
final Color brandYellow = Color(0xffFFB039);
final Color backgroundOrange = const Color.fromARGB(20, 254, 87, 15);
}
......@@ -8,9 +8,15 @@ class ImporterProvider with ChangeNotifier {
ImporterProvider(this.podService) {
// TODO: implement
}
Item? activeWhatsappPlugin = null;
Item? selectedPlugin = null;
bool get isWhatsappActive => activeWhatsappPlugin != null;
bool get isWhatsappSelected =>
isWhatsappActive && selectedPlugin == activeWhatsappPlugin;
Future<void> getActiveImporters() async {
var pluginItems = await podService.graphql(query: """
query {
......@@ -37,7 +43,11 @@ query {
}
void setActivePlugin(Item? plugin) {
selectedPlugin = plugin;
if (selectedPlugin != plugin) {
selectedPlugin = plugin;
} else {
selectedPlugin = null;
}
notifyListeners();
}
}
......@@ -31,7 +31,7 @@ class ProjectProvider with ChangeNotifier {
String errorMessage = "";
bool whatsappSelected = false;
bool whatsappDataInpod = false;
bool whatsappDataInPod = false;
List<Item> projects = [];
Map<String, DatasetSummary> datasetSummaries = {};
......@@ -116,7 +116,7 @@ query {
}
""");
whatsappDataInpod = items.length > 0;
whatsappDataInPod = items.length > 0;
notifyListeners();
}
......@@ -168,8 +168,7 @@ query {
}
resetProjectState();
var projectQuery =
"""
var projectQuery = """
query {
Project (filter: {id: {eq: "$projectId"}}) {
name
......@@ -223,8 +222,7 @@ query {
}
Future<bool> projectNameExists(String projectName) async {
String query =
'''
String query = '''
query {
Project (filter: {deleted: {eq: 0}}){
name
......@@ -236,8 +234,7 @@ query {
}
getProjectSummaries() async {
String query =
'''
String query = '''
query {
Project(limit: 1000, filter: {deleted: {eq: 0}}) {
id
......@@ -342,8 +339,7 @@ query {
currentProject!.edges["dataset"] =
EdgeList(name: "dataset", targets: [dataset]);
String messageQuery =
'''
String messageQuery = '''
query {
Message (limit: 500) {
id
......@@ -721,8 +717,7 @@ query {
Stream<Item> OauthItemStream() async* {
while (true) {
await Future.delayed(Duration(seconds: 1));
var query =
'''
var query = '''
query {
OauthFlow (limit: 500) {
accessToken
......@@ -754,8 +749,7 @@ query {
Future<Item?> getOauthItem() async {
// TODO use this in stream
var query =
'''
var query = '''
query {
OauthFlow (limit: 500) {
accessToken
......
......@@ -49,7 +49,13 @@ class _AppsScreenState extends State<AppsScreen> {
children: [
_buildInboxTile(),
if (provider.appListState == AppListState.fetching)
CircularProgressIndicator(color: app.colors.primary)
Container(
width: MediaQuery.of(context).size.width,
padding: const EdgeInsets.symmetric(vertical: 20),
child: Center(
child: CircularProgressIndicator(
color: app.colors.primary)),
)
else if (provider.appListState == AppListState.fetched)
dataApps.isEmpty
? _buildEmptyState()
......@@ -113,7 +119,7 @@ class _AppsScreenState extends State<AppsScreen> {
return Column(
children: List.generate(dataApps.length, (index) {
return Padding(
padding: const EdgeInsets.only(top: 15),
padding: const EdgeInsets.only(top: 30),
child: _buildTile(
title: dataApps[index].get("name") ?? "Unnamed",
description: dataApps[index].get("pluginDescription") ?? "",
......
......@@ -5,6 +5,8 @@ import 'package:memri/providers/importer_provider.dart';
import 'package:memri/providers/navigation_provider.dart';
import 'package:memri/utilities/helpers/app_helper.dart';
import 'package:memri/utilities/helpers/responsive_helper.dart';
import 'package:memri/widgets/empty.dart';
import 'package:memri/widgets/importer_tile.dart';
import 'package:memri/widgets/scaffold/workspace_scaffold.dart';
import 'package:provider/provider.dart';
......@@ -23,6 +25,9 @@ class _DataScreenState extends State<DataScreen> {
late final importerProvider =
Provider.of<ImporterProvider>(context, listen: false);
ScrollController _bodyScrollController = ScrollController();
final ScrollController _sideBarScrollController = ScrollController();
@override
void initState() {
importerProvider.getActiveImporters();
......@@ -33,256 +38,239 @@ class _DataScreenState extends State<DataScreen> {
Widget build(BuildContext context) {
return WorkspaceScaffold(
currentItem: NavigationItem.data,
child: SingleChildScrollView(
child: Consumer<ImporterProvider>(builder: (context, provider, _) {
return Container(
width: MediaQuery.of(context).size.width,
color: app.colors.greyBackGround,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
flex: 3,
child: Container(
color: app.colors.white,
padding: EdgeInsets.all(30),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (!ResponsiveHelper(context).isSmallScreen)
SizedBox(height: 16),
Row(
children: [
Text("Data streams", style: AppStyles.headline2),
Spacer(),
TextButton(
style: ButtonStyle(
padding: MaterialStateProperty.all(
EdgeInsets.all(0))),
onPressed:
_navigationProvider.openDataExplorerLink,
child: Text(
'Open data explorer',
style: AppStyles.buttonLabel
.copyWith(color: Color(0xffFE570F)),
),
),
if (!ResponsiveHelper(context).isSmallScreen)
Spacer(),
],
),
SizedBox(height: 30),
Wrap(
spacing: 30,
runSpacing: 30,
children: [
buildBox(
title: 'WhatsApp',
description: '',
size: '',
status: 'Connect',
onTap: () {
if (provider.activeWhatsappPlugin == null) {
RouteNavigator.navigateTo(
context: context,
route: Routes.importerConnect,
param: {'type': 'whatsapp'},
);
} else {
provider.setActivePlugin(
provider.activeWhatsappPlugin);
}
}),
buildBox(
title: 'Create new importer',
description: '',
size: '',
status: 'Learn how to create your own importer',
highlight: true,
onTap: () => RouteNavigator.navigateTo(
route: Routes.importerCreate,
context: context),
),
],
),
SizedBox(height: 150),
],
),
),
),
SizedBox(
width: 1,
),
if (provider.selectedPlugin != null)
Expanded(
flex: 1,
child: Container(
// decoration: BoxDecoration(border: Border(left: BorderSide(color: app.colors.brandGreyText))),
color: app.colors.white,
padding: EdgeInsets.fromLTRB(16, 64, 16, 32),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"selected".toUpperCase(),
style: AppStyles.smallCaps
.copyWith(color: app.colors.brandGreyText),
),
SizedBox(
height: 16,
),
Row(
children: [
Text(
provider.selectedPlugin
?.get("pluginName")
.replaceAll("Plugin", "") ??
"unknown plugin",
style: AppStyles.headline2
.copyWith(color: app.colors.brandOrange),
),
Spacer(),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
"status".toUpperCase(),
style: AppStyles.smallCaps.copyWith(
color: app.colors.brandGreyText),
),
Text(
provider.selectedPlugin
?.get("status") ??
"status unknown",
style: AppStyles.ul)
],
)
],
),
SizedBox(
height: 16,
),
Row(
children: [
Spacer(),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
"in the pod".toUpperCase(),
style: AppStyles.smallCaps.copyWith(
color: app.colors.brandGreyText),
),
Text(
((provider.selectedPlugin
?.get("progress") ??
1.0) *
100)
.toString() +
"%",
style: AppStyles.ul,
)
],
)
],
),
SizedBox(
height: 64,
),
TextButton(
onPressed: () => {
RouteNavigator.navigateTo(
route: Routes.projectsCreate,
context: context)
},
child: SizedBox(
height: 36,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text("Create new project"),
],
)),
style: primaryButtonStyle,
)
],
),
))
],
child: Consumer<ImporterProvider>(builder: (context, provider, _) {
return ResponsiveHelper(context).isSmallScreen
? _buildMobileBody(provider)
: _buildDesktopBody(provider);
}),
);
}
Widget _buildDesktopBody(ImporterProvider provider) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
flex: ResponsiveHelper(context).isMediumScreen ? 5 : 3,
child: Container(
color: app.colors.white,
child: SingleChildScrollView(
controller: _bodyScrollController,
child: _buildBody(provider),
),
);
}),
),
),
),
if (provider.selectedPlugin != null) SizedBox(width: 2),
if (provider.selectedPlugin != null)
Expanded(
flex: ResponsiveHelper(context).isMediumScreen ? 3 : 1,
child: SingleChildScrollView(
controller: _sideBarScrollController,
child: Container(
color: app.colors.white,
padding: EdgeInsets.all(20),
child: _buildSideBar(provider),
),
),
),
],
);
}
}
Widget buildBox({
required String title,
required String description,
required String size,
required String status,
VoidCallback? onTap,
bool selected = false,
bool highlight = false,
}) {
return InkWell(
onTap: onTap,
child: Container(
width: 205,
height: 95,
decoration: selected
? BoxDecoration(
border: Border.all(color: app.colors.brandOrange),
color: app.colors.backgroundOrange)
: BoxDecoration(
Widget _buildMobileBody(ImporterProvider provider) {
_bodyScrollController = ScrollController();
return SingleChildScrollView(
controller: _bodyScrollController,
child: Column(
children: [
_buildBody(provider),
if (provider.selectedPlugin != null) SizedBox(height: 2),
if (provider.selectedPlugin != null)
Container(
color: app.colors.white,
border: Border.all(color: app.colors.brandLineGrey, width: 1),
padding: EdgeInsets.all(30),
child: _buildSideBar(provider),
),
child: Stack(
],
),
);
}
_buildBody(ImporterProvider provider) {
return Container(
width: MediaQuery.of(context).size.width,
color: app.colors.white,
padding: EdgeInsets.symmetric(horizontal: 30),
child: Row(
children: [
Positioned(
top: 10,
right: 10,
left: 10,
child: Text(
title,
style: AppStyles.headline3.copyWith(
fontSize: 15,
fontWeight: FontWeight.bold,
color: highlight
? app.colors.brandBlack
: app.colors.brandGreyText),
),
),
Positioned(
bottom: 10,
right: 10,
left: 10,
Expanded(
flex: ResponsiveHelper(context).isMediumScreen ? 5 : 3,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
description,
style: AppStyles.bodyTiny.copyWith(color: Color(0xff989898)),
),
Text(
size,
style: AppStyles.bodyTiny.copyWith(color: Color(0xff989898)),
SizedBox(height: 20),
if (!ResponsiveHelper(context).isSmallScreen)
SizedBox(height: 20),
Row(
children: [
Text(
"Data streams",
style: AppStyles.headline2,
),
Spacer(flex: 5),
TextButton(
style: ButtonStyle(
padding:
MaterialStateProperty.all(EdgeInsets.all(0))),
onPressed: _navigationProvider.openDataExplorerLink,
child: Text(
'Open data explorer',
style: AppStyles.buttonLabel
.copyWith(color: Color(0xffFE570F)),
),
),
// if (!ResponsiveHelper(context).isSmallScreen &&
// !provider.isWhatsappSelected)
// Spacer(flex: 2),
],
),
Text(
status,
style: AppStyles.bodyTiny.copyWith(
fontWeight: FontWeight.w700,
color:
selected ? Color(0xff15B599) : app.colors.brandOrange,
),
SizedBox(height: 30),
Wrap(
spacing: 30,
runSpacing: 30,
children: [
ImporterTile(
title: 'WhatsApp',
status: provider.isWhatsappActive ? 'Running' : 'Connect',
statusColor: provider.isWhatsappActive
? app.colors.brandGreen
: null,
active: provider.isWhatsappActive,
selected: provider.isWhatsappSelected,
onTap: () {
if (!provider.isWhatsappActive) {
RouteNavigator.navigateTo(
context: context,
route: Routes.importerConnect,
param: {'type': 'whatsapp'},
);
} else {
provider
.setActivePlugin(provider.activeWhatsappPlugin);
}
},
),
ImporterTile(
title: 'Create new importer',
status: 'Learn how to create your own importer',
selectable: false,
onTap: () => RouteNavigator.navigateTo(
route: Routes.importerCreate,
context: context,
),
),
],
),
SizedBox(height: 20),
if (!ResponsiveHelper(context).isSmallScreen)
SizedBox(height: 130),
],
),
),
if (!provider.isWhatsappSelected)
Expanded(
flex: ResponsiveHelper(context).isMediumScreen ? 3 : 1,
child: Empty(),
),
],
),
);
}
_buildSideBar(ImporterProvider provider) {
return Container(
color: app.colors.white,
padding: EdgeInsets.symmetric(horizontal: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 20),
if (!ResponsiveHelper(context).isSmallScreen) SizedBox(height: 20),
Text(
"selected".toUpperCase(),
style:
AppStyles.smallCaps.copyWith(color: app.colors.brandGreyText),
),
SizedBox(height: 30),
Row(
children: [
Text(
provider.selectedPlugin
?.get("pluginName")
.replaceAll("Plugin", "") ??
"unknown plugin",
style:
AppStyles.headline2.copyWith(color: app.colors.brandOrange),
),
Spacer(),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
"status".toUpperCase(),
style: AppStyles.smallCaps
.copyWith(color: app.colors.brandGreyText),
),
Text(
provider.selectedPlugin?.get("status") ??
"status unknown",
style: AppStyles.ul)
],
)
],
),
SizedBox(height: 20),
Row(
children: [
Spacer(),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
"in the pod".toUpperCase(),
style: AppStyles.smallCaps
.copyWith(color: app.colors.brandGreyText),
),
Text(
((provider.selectedPlugin?.get("progress") ?? 1.0) * 100)
.toString() +
"%",
style: AppStyles.ul,
)
],
)
],
),
SizedBox(height: 50),
TextButton(
onPressed: () => {
RouteNavigator.navigateTo(
route: Routes.projectsCreate, context: context)
},
child: SizedBox(
height: 36,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text("Create new project"),
],
)),
style: primaryButtonStyle,
),
SizedBox(height: 20),
if (!ResponsiveHelper(context).isSmallScreen) SizedBox(height: 20),
],
),
),
);
);
}
}
......@@ -45,13 +45,13 @@ class _ProjectsAppPreviewScreen extends State<ProjectsAppPreviewScreen> {
var dataAppProvider = Provider.of<DataAppProvider>(context, listen: false);
// for debugging, don't run app hardcode ID
var projId = 354;
dataAppProvider.currentAppState = AppState.showApp;
dataAppProvider.currentPluginMessages =
await dataAppProvider.loadAppContent("_preview-$projId");
// var projId = 342;
// dataAppProvider.currentAppState = AppState.showApp;
// dataAppProvider.currentPluginMessages =
// await dataAppProvider.loadAppContent("_preview-$projId");
// var projId = projectProvider.gitlabProjectId;
dataAppProvider.runPluginFromGit(gitProjectId: projId, changeState: true);
var projId = projectProvider.gitlabProjectId;
dataAppProvider.runPluginFromGit(gitProjectId: projId!, changeState: true);
}
@override
......
......@@ -2,10 +2,10 @@ import 'package:flutter/material.dart';
import 'package:memri/configs/routes/route_navigator.dart';
import 'package:memri/constants/app_styles.dart';
import 'package:memri/providers/project_provider.dart';
import 'package:memri/screens/workspace/data_screen.dart';
import 'package:memri/utilities/helpers/app_helper.dart';
import 'package:memri/utilities/helpers/responsive_helper.dart';
import 'package:memri/widgets/components/error_message.dart';
import 'package:memri/widgets/importer_tile.dart';
import 'package:memri/widgets/project/project_progress_bar.dart';
import 'package:memri/widgets/scaffold/workspace_scaffold.dart';
import 'package:memri/widgets/simple_text_editor.dart';
......@@ -127,10 +127,8 @@ class _ProjectsCreateScreenState extends State<ProjectsCreateScreen> {
"Select the data source for your new app. You may only select one.",
style: AppStyles.bodyText1),
SizedBox(height: 20),
buildBox(
title: 'Whatsapp',
description: '',
size: '',
ImporterTile(
title: 'WhatsApp',
status: 'ACTIVE',
selected: provider.whatsappSelected,
onTap: () => provider.handleSelectDataSource(),
......
......@@ -97,7 +97,7 @@ class _ProjectsScreenState extends State<ProjectsScreen> {
}
Widget _buildBody(ProjectProvider provider) =>
(provider.whatsappDataInpod || provider.projects.isEmpty)
(provider.whatsappDataInPod || provider.projects.isEmpty)
? _buildEmptyState(provider)
: _buildProjectList(provider);
......@@ -354,12 +354,12 @@ class _ProjectsScreenState extends State<ProjectsScreen> {
style: AppStyles.bodyText1.copyWith(fontSize: 14),
),
SizedBox(height: 50),
ProjectProgressSteps(step: provider.whatsappDataInpod ? 2 : 1),
ProjectProgressSteps(step: provider.whatsappDataInPod ? 2 : 1),
SizedBox(height: 50),
TextButton(
onPressed: () => RouteNavigator.navigateTo(
context: context,
route: provider.whatsappDataInpod
route: provider.whatsappDataInPod
? Routes.projectsCreate
: Routes.data),
style: primaryButtonStyle,
......@@ -368,7 +368,7 @@ class _ProjectsScreenState extends State<ProjectsScreen> {
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(provider.whatsappDataInpod
Text(provider.whatsappDataInPod
? "Create your project"
: "Connect data"),
SizedBox(width: 10),
......
......@@ -4,6 +4,7 @@ import 'package:memri/constants/app_images.dart';
import 'package:memri/constants/app_keys.dart';
import 'package:memri/constants/app_locales.dart';
import 'package:memri/constants/app_settings.dart';
import 'package:memri/constants/app_styles.dart';
import 'package:uuid/uuid.dart';
class ApplicationHelper {
......@@ -25,6 +26,8 @@ class ApplicationHelper {
AppKeys get keys => AppKeys();
AppStyles get styles => AppStyles();
String randomUuid() => Uuid().v4().replaceAll("-", "");
}
......
import 'package:flutter/material.dart';
import 'package:memri/constants/app_styles.dart';
import 'package:memri/utilities/helpers/app_helper.dart';
class ImporterTile extends StatelessWidget {
const ImporterTile({
Key? key,
required this.title,
required this.status,
required this.onTap,
this.featureVariables,
this.storageSize,
this.selectable = true,
this.selected = false,
this.active = false,
this.statusColor,
}) : super(key: key);
final String title;
final int? featureVariables;
final String? storageSize;
final String status;
final VoidCallback? onTap;
final bool selectable;
final bool selected;
final bool active;
final Color? statusColor;
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onTap,
child: Container(
width: 205,
height: 95,
decoration: selected
? BoxDecoration(
border: Border.all(color: app.colors.brandOrange),
color: app.colors.backgroundOrange)
: BoxDecoration(
color: active && selectable
? app.colors.greyBackGround
: app.colors.white,
border: Border.all(color: app.colors.brandLineGrey, width: 1),
),
child: Stack(
children: [
Positioned(
top: 10,
right: 10,
left: 10,
child: Text(
title,
style: AppStyles.headline3.copyWith(
fontSize: 15,
fontWeight: FontWeight.bold,
color: selected
? app.colors.brandOrange
: active || !selectable
? app.colors.brandBlack
: app.colors.brandGreyText),
),
),
Positioned(
bottom: 10,
right: 10,
left: 10,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (featureVariables != null)
Text(
'$featureVariables feature variables',
style: AppStyles.bodyTiny
.copyWith(color: app.colors.brandGrey),
),
if (storageSize != null)
Text(
storageSize!,
style: AppStyles.bodyTiny
.copyWith(color: app.colors.brandGrey),
),
Text(
status,
style: AppStyles.bodyTiny.copyWith(
fontWeight: FontWeight.w700,
color: selected
? app.colors.brandOrange
: statusColor ?? app.colors.brandOrange,
),
),
],
),
),
],
),
),
);
}
}
......@@ -76,6 +76,12 @@ class BaseScaffold extends StatelessWidget {
}
Widget _buildSplash(AppProvider provider) {
String podVersion;
if (provider.podVersion == null) {
podVersion = S.current.initializing;
} else {
podVersion = 'V.${provider.podVersion}';
}
return Stack(
children: [
LoadingIndicator(message: provider.welcomeMessage),
......@@ -85,7 +91,7 @@ class BaseScaffold extends StatelessWidget {
right: 0,
child: Column(
children: [
Text('POD: V.${provider.podVersion ?? S.current.initializing}'),
Text('POD: $podVersion'),
Text('APP: V.${provider.appVersion ?? 'x.x.x.x'}'),
],
),
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment