Skip to content
Snippets Groups Projects
Commit f2bdff42 authored by anfeichtinger's avatar anfeichtinger
Browse files

Revert "initial rewrite"

This reverts commit 1ceadda1.
parent ee8c3b30
No related branches found
No related tags found
No related merge requests found
Showing
with 362 additions and 43 deletions
......@@ -14,8 +14,8 @@ This repository requires [Flutter](https://flutter.dev/docs/get-started/install)
Clone the project and enter the project folder.
```sh
git clone https://github.com/anfeichtinger/timebox.git
cd timebox
git clone https://github.com/anfeichtinger/flutter_production_boilerplate.git
cd flutter_production_boilerplate
```
You can remove the screenshots located in [assets/img/](./assets/img).
......
......@@ -34,7 +34,7 @@ android {
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "dev.feichtinger.flutterproductionboilerplate.timebox"
applicationId "dev.feichtinger.flutterproductionboilerplate.flutter_production_boilerplate"
minSdkVersion 23
targetSdkVersion 30
versionCode flutterVersionCode.toInteger()
......
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="dev.feichtinger.flutterproductionboilerplate.timebox">
package="dev.feichtinger.flutterproductionboilerplate.flutter_production_boilerplate">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
......
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="dev.feichtinger.flutterproductionboilerplate.timebox">
package="dev.feichtinger.flutterproductionboilerplate.flutter_production_boilerplate">
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
......@@ -7,7 +7,7 @@
</intent>
</queries>
<application
android:label="timebox"
android:label="flutter_production_boilerplate"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
......
package dev.feichtinger.flutterproductionboilerplate.timebox
package dev.feichtinger.flutterproductionboilerplate.flutter_production_boilerplate
import io.flutter.embedding.android.FlutterActivity
......
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="dev.feichtinger.flutterproductionboilerplate.timebox">
package="dev.feichtinger.flutterproductionboilerplate.flutter_production_boilerplate">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
......
......@@ -11,7 +11,7 @@
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>timebox</string>
<string>flutter_production_boilerplate</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
......
import 'package:bloc/bloc.dart';
class BottomNavCubit extends Cubit<int> {
BottomNavCubit() : super(0);
void updateIndex(int index) => emit(index);
void getFirstScreen() => emit(0);
void getSecondScreen() => emit(1);
}
import 'package:bloc/bloc.dart';
class DateTimeCubit extends Cubit<DateTime> {
DateTimeCubit() : super(DateTime.now());
void selectDateTime(DateTime dateTime) => emit(dateTime);
}
import 'package:equatable/equatable.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:timebox/config/theme.dart';
import 'package:flutter_production_boilerplate/config/theme.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart';
part 'theme_state.dart';
......
......@@ -4,8 +4,8 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_displaymode/flutter_displaymode.dart';
import 'package:timebox/cubit/theme_cubit.dart';
import 'package:timebox/ui/screens/skeleton_screen.dart';
import 'package:flutter_production_boilerplate/cubit/theme_cubit.dart';
import 'package:flutter_production_boilerplate/ui/screens/skeleton_screen.dart';
import 'package:hive/hive.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart';
import 'package:path_provider/path_provider.dart';
......
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_production_boilerplate/config/theme.dart';
import 'package:flutter_production_boilerplate/cubit/theme_cubit.dart';
import 'package:flutter_production_boilerplate/ui/widgets/header.dart';
import 'package:flutter_production_boilerplate/ui/widgets/first_screen/info_card.dart';
import 'package:ionicons/ionicons.dart';
class FirstScreen extends StatelessWidget {
const FirstScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Material(
color: Theme.of(context).backgroundColor,
child: ListView(
padding: const EdgeInsets.symmetric(horizontal: 16),
physics: const BouncingScrollPhysics(),
children: [
const Header(text: 'app_name'),
Card(
elevation: 2,
color: Theme.of(context).cardColor,
/// Example: Getting border radius circular as const
/// Nested Widgets do not need to be declared as const.
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(8))),
child: SwitchListTile(
onChanged: (bool newValue) {
/// Example: Change theme with Cubit
BlocProvider.of<ThemeCubit>(context).getTheme(ThemeState(
newValue ? AppThemes.darkTheme : AppThemes.lightTheme));
},
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(8))),
value: Theme.of(context).brightness == Brightness.dark,
title: Row(
children: [
/// Examle: Ionicons
/// Available icons -> https://ionic.io/ionicons
Icon(Ionicons.moon_outline,
color: Theme.of(context).primaryColor),
const SizedBox(width: 16),
Text(
/// Example: Use the easy_translations package
tr('dark_mode_title'),
style: Theme.of(context)
.textTheme
.subtitle1!
.apply(fontWeightDelta: 2),
),
],
),
),
),
/// Example: Good way to add space between items
const SizedBox(height: 8),
Card(
elevation: 2,
/// Example: Many items have their own colors inside of the ThemData
/// You can overwrite them in [config/theme.dart].
color: Theme.of(context).cardColor,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(8))),
child: SwitchListTile(
onChanged: (bool newValue) {
/// Example: Change locale
/// The initial locale is automatically determined by the library.
/// Changing the locale like this will persist the selected locale.
context.setLocale(
newValue ? const Locale('de') : const Locale('en'));
},
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(8))),
value: context.locale == const Locale('de'),
title: Row(
children: [
Icon(Ionicons.text_outline,
color: Theme.of(context).primaryColor),
const SizedBox(width: 16),
Text(
tr('language_switch_title'),
style: Theme.of(context)
.textTheme
.subtitle1!
.apply(fontWeightDelta: 2),
),
],
),
),
),
const SizedBox(height: 8),
GridView.count(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
crossAxisCount: 2,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
childAspectRatio: 4 / 5,
children: const [
/// Example: it is good practice to put widgets in separate files.
/// This way the screen files won't become too large and
/// the code becomes more clear.
InfoCard(
title: 'localization_title',
content: 'localization_content',
icon: Ionicons.text_outline,
isPrimaryColor: true),
InfoCard(
title: 'linting_title',
content: 'linting_content',
icon: Ionicons.options_outline,
isPrimaryColor: false),
InfoCard(
title: 'storage_title',
content: 'storage_content',
icon: Ionicons.folder_outline,
isPrimaryColor: false),
InfoCard(
title: 'dark_mode_title',
content: 'dark_mode_content',
icon: Ionicons.moon_outline,
isPrimaryColor: true),
InfoCard(
title: 'state_title',
content: 'state_content',
icon: Ionicons.notifications_outline,
isPrimaryColor: true),
InfoCard(
title: 'display_title',
content: 'display_content',
icon: Ionicons.speedometer_outline,
isPrimaryColor: false),
],
),
const SizedBox(height: 36),
]),
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_production_boilerplate/ui/widgets/header.dart';
import 'package:flutter_production_boilerplate/ui/widgets/second_screen/grid_item.dart';
import 'package:flutter_production_boilerplate/ui/widgets/second_screen/link_card.dart';
import 'package:flutter_production_boilerplate/ui/widgets/second_screen/text_divider.dart';
import 'package:ionicons/ionicons.dart';
class SecondScreen extends StatelessWidget {
const SecondScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Material(
color: Theme.of(context).backgroundColor,
child: ListView(
padding: const EdgeInsets.symmetric(horizontal: 16),
physics: const BouncingScrollPhysics(),
children: [
const Header(text: 'bottom_nav_second'),
const LinkCard(
title: 'github_card_title',
icon: Ionicons.logo_github,
url:
'https://github.com/anfeichtinger/flutter_production_boilerplate'),
const TextDivider(text: 'author_divider_title'),
const LinkCard(
title: 'website_card_title',
icon: Ionicons.person_circle_outline,
url: 'https://feichtinger.dev'),
const SizedBox(height: 8),
GridView.count(
physics: const NeverScrollableScrollPhysics(),
crossAxisCount: 2,
childAspectRatio: 2 / 1,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
shrinkWrap: true,
children: const [
GridItem(
title: 'instagram_card_title',
icon: Ionicons.logo_instagram,
url: 'https://www.instagram.com/anfeichtinger',
),
GridItem(
title: 'twitter_card_title',
icon: Ionicons.logo_twitter,
url: 'https://twitter.com/_pharrax',
),
GridItem(
title: 'donate_card_title',
icon: Ionicons.heart_outline,
url:
'https://www.paypal.com/donate?hosted_button_id=EE3W7PS6AHEP8&source=url',
),
],
),
const TextDivider(text: 'packages_divider_title'),
GridView.count(
physics: const NeverScrollableScrollPhysics(),
crossAxisCount: 2,
childAspectRatio: 2 / 1,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
shrinkWrap: true,
children: const [
GridItem(
title: 'flutter_bloc',
icon: Ionicons.apps_outline,
url: 'https://pub.dev/packages/flutter_bloc',
),
GridItem(
title: 'bloc',
icon: Ionicons.grid_outline,
url: 'https://pub.dev/packages/bloc',
),
GridItem(
title: 'hydrated_bloc',
icon: Ionicons.folder_open_outline,
url: 'https://pub.dev/packages/hydrated_bloc',
),
GridItem(
title: 'equatable',
icon: Ionicons.git_compare_outline,
url: 'https://pub.dev/packages/equatable',
),
GridItem(
title: 'lints',
icon: Ionicons.options_outline,
url: 'https://pub.dev/packages/flutter_lints',
),
GridItem(
title: 'path_provider',
icon: Ionicons.extension_puzzle_outline,
url: 'https://pub.dev/packages/path_provider',
),
GridItem(
title: 'flutter_displaymode',
icon: Ionicons.speedometer_outline,
url: 'https://pub.dev/packages/flutter_displaymode',
),
GridItem(
title: 'easy_localization',
icon: Ionicons.text_outline,
url: 'https://pub.dev/packages/easy_localization',
),
GridItem(
title: 'hive',
icon: Ionicons.folder_outline,
url: 'https://pub.dev/packages/hive',
),
GridItem(
title: 'url_launcher',
icon: Ionicons.share_outline,
url: 'https://pub.dev/packages/url_launcher',
),
GridItem(
title: 'ionicons',
icon: Ionicons.logo_ionic,
url: 'https://pub.dev/packages/ionicons',
),
],
),
const SizedBox(height: 36),
]),
);
}
}
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:timebox/cubit/date_time_cubit.dart';
import 'package:timebox/ui/widgets/app_bar_gone.dart';
import 'package:flutter_production_boilerplate/cubit/bottom_nav_cubit.dart';
import 'package:flutter_production_boilerplate/ui/screens/first_screen.dart';
import 'package:flutter_production_boilerplate/ui/screens/second_screen.dart';
import 'package:flutter_production_boilerplate/ui/widgets/app_bar_gone.dart';
import 'package:flutter_production_boilerplate/ui/widgets/bottom_nav_bar.dart';
class SkeletonScreen extends StatelessWidget {
const SkeletonScreen({Key? key}) : super(key: key);
final _pageNavigation = const [
FirstScreen(),
SecondScreen(),
];
@override
Widget build(BuildContext context) {
return BlocProvider<BottomNavCubit>(
......@@ -15,8 +23,14 @@ class SkeletonScreen extends StatelessWidget {
builder: (BuildContext context, int state) {
return Scaffold(
appBar: const AppBarGone(),
body: ListView.builder(itemBuilder: itemBuilder),
bottomNavigationBar: BottomAppBar(),
/// When switching between tabs this will fade the old
/// layout out and the new layout in.
body: AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: _pageNavigation.elementAt(state)),
/// Cannot be const, tab status will not update.
bottomNavigationBar: BottomNavBar(),
);
},
),
......
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_production_boilerplate/cubit/bottom_nav_cubit.dart';
import 'package:ionicons/ionicons.dart';
class BottomApplicationBar extends StatelessWidget {
final List<Widget> leftWidgets;
final List<Widget> rightWidgets;
const BottomApplicationBar(
{Key? key, required this.leftWidgets, required this.rightWidgets})
: super(key: key);
class BottomNavBar extends StatelessWidget {
/// It is okay not to use a const constructor here.
/// Using const breaks updating of selected BottomNavigationBarItem.
// ignore: prefer_const_constructors_in_immutables
BottomNavBar({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.only(top: 2, right: 8, left: 8),
elevation: 4,
color: Theme.of(context).bottomAppBarColor,
shape: const RoundedRectangleBorder(
......@@ -19,19 +22,24 @@ class BottomApplicationBar extends StatelessWidget {
topRight: Radius.circular(12),
),
),
child: BottomAppBar(
color: Theme.of(context).bottomAppBarColor,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
Row(children: leftWidgets),
const Spacer(),
Row(children: rightWidgets),
],
child: BottomNavigationBar(
currentIndex: context.read<BottomNavCubit>().state,
onTap: (index) => context.read<BottomNavCubit>().updateIndex(index),
type: BottomNavigationBarType.fixed,
elevation: 0,
backgroundColor: Colors.transparent,
selectedItemColor: Theme.of(context).primaryColor,
unselectedItemColor: Theme.of(context).textTheme.bodyText1!.color,
items: [
BottomNavigationBarItem(
icon: const Icon(Ionicons.home_outline),
label: tr('bottom_nav_first'),
),
),
BottomNavigationBarItem(
icon: const Icon(Ionicons.information_circle_outline),
label: tr('bottom_nav_second'),
),
],
),
);
}
......
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
class Header extends StatelessWidget {
final String text;
const Header({Key? key, required this.text}) : super(key: key);
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 2.0, vertical: 36),
child: Text(
tr(text),
textAlign: TextAlign.start,
style:
Theme.of(context).textTheme.headline4!.apply(fontFamily: 'Poppins'),
),
);
}
}
name: timebox
name: flutter_production_boilerplate
description: A new Flutter project containing bloc, hive & easy localization.
# The following line prevents the package from being accidentally published to
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment