forked from SelfPrivacy/selfprivacy.org.app
update
parent
e849b551fc
commit
d3f494adeb
@ -1,7 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
final shadow8 = BoxShadow(
|
||||
offset: Offset(0, 4),
|
||||
blurRadius: 8,
|
||||
color: Colors.black.withOpacity(.08),
|
||||
);
|
@ -0,0 +1,27 @@
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:selfprivacy/logic/models/job.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
export 'package:provider/provider.dart';
|
||||
|
||||
part 'jobs_state.dart';
|
||||
|
||||
class JobsCubit extends Cubit<JobsState> {
|
||||
JobsCubit() : super(JobsState.emtpy());
|
||||
|
||||
List<Job> jobsList = [];
|
||||
|
||||
void addJob(Job job) {
|
||||
final newState = state.addJob(job);
|
||||
emit(newState);
|
||||
}
|
||||
|
||||
void removeJob(String id) {
|
||||
final newState = state.removeById(id);
|
||||
emit(newState);
|
||||
}
|
||||
|
||||
void applyAll() {
|
||||
print(state.jobList);
|
||||
emit(JobsState.emtpy());
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
part of 'jobs_cubit.dart';
|
||||
|
||||
class JobsState extends Equatable {
|
||||
const JobsState(this.jobList);
|
||||
|
||||
final List<Job> jobList;
|
||||
|
||||
static JobsState emtpy() => JobsState([]);
|
||||
|
||||
bool get isEmpty => jobList.isEmpty;
|
||||
|
||||
JobsState addJob(Job job) {
|
||||
var newJobsList = [...jobList];
|
||||
newJobsList.add(job);
|
||||
return JobsState(newJobsList);
|
||||
}
|
||||
|
||||
JobsState removeById(String id) {
|
||||
var newJobsList = jobList.where((element) => element.id != id).toList();
|
||||
return JobsState(newJobsList);
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object> get props => jobList;
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:selfprivacy/utils/password_generator2.dart';
|
||||
|
||||
class Job extends Equatable {
|
||||
Job({
|
||||
String? id,
|
||||
required this.title,
|
||||
}) : id = id ?? getRandomString(5);
|
||||
|
||||
final String title;
|
||||
final String id;
|
||||
|
||||
@override
|
||||
List<Object> get props => [id, title];
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:selfprivacy/config/brand_theme.dart';
|
||||
|
||||
class BrandBottomSheet extends StatelessWidget {
|
||||
const BrandBottomSheet({Key? key, required this.child}) : super(key: key);
|
||||
|
||||
final Widget child;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
height: MediaQuery.of(context).size.height -
|
||||
MediaQuery.of(context).padding.top -
|
||||
60,
|
||||
child: Scaffold(
|
||||
body: SingleChildScrollView(
|
||||
physics: ClampingScrollPhysics(),
|
||||
child: Container(
|
||||
padding: paddingH15V0,
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:selfprivacy/config/brand_colors.dart';
|
||||
import 'package:selfprivacy/utils/extensions/elevation_extension.dart';
|
||||
|
||||
class BrandCard extends StatelessWidget {
|
||||
const BrandCard({
|
||||
Key? key,
|
||||
this.child,
|
||||
}) : super(key: key);
|
||||
|
||||
final Widget? child;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).brightness == Brightness.dark
|
||||
? BrandColors.black
|
||||
: BrandColors.white,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
).ev8,
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 20,
|
||||
vertical: 15,
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:selfprivacy/config/brand_colors.dart';
|
||||
|
||||
class BrandCards {
|
||||
static Widget big({required Widget child}) => _BrandCard(
|
||||
child: child,
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 20,
|
||||
vertical: 15,
|
||||
),
|
||||
shadow: bigShadow,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
);
|
||||
static Widget small({required Widget child}) => _BrandCard(
|
||||
child: child,
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 15,
|
||||
vertical: 10,
|
||||
),
|
||||
shadow: bigShadow,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
);
|
||||
}
|
||||
|
||||
class _BrandCard extends StatelessWidget {
|
||||
const _BrandCard({
|
||||
Key? key,
|
||||
required this.child,
|
||||
required this.padding,
|
||||
required this.shadow,
|
||||
required this.borderRadius,
|
||||
}) : super(key: key);
|
||||
|
||||
final Widget child;
|
||||
final EdgeInsets padding;
|
||||
final List<BoxShadow> shadow;
|
||||
final BorderRadius borderRadius;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).brightness == Brightness.dark
|
||||
? BrandColors.black
|
||||
: BrandColors.white,
|
||||
borderRadius: borderRadius,
|
||||
boxShadow: shadow,
|
||||
),
|
||||
padding: padding,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final bigShadow = [
|
||||
BoxShadow(
|
||||
offset: Offset(0, 4),
|
||||
blurRadius: 8,
|
||||
color: Colors.black.withOpacity(.08),
|
||||
)
|
||||
];
|
@ -0,0 +1,67 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:selfprivacy/config/brand_colors.dart';
|
||||
import 'package:selfprivacy/logic/cubit/jobs/jobs_cubit.dart';
|
||||
import 'package:selfprivacy/ui/components/brand_button/brand_button.dart';
|
||||
import 'package:selfprivacy/ui/components/brand_cards/brand_cards.dart';
|
||||
import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
|
||||
|
||||
class JobsContent extends StatelessWidget {
|
||||
const JobsContent({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var jobs = context.watch<JobsCubit>().state;
|
||||
return Column(
|
||||
children: [
|
||||
SizedBox(height: 15),
|
||||
Center(
|
||||
child: BrandText.h2(
|
||||
'jobs.title'.tr(),
|
||||
),
|
||||
),
|
||||
if (jobs.isEmpty)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 50),
|
||||
child: BrandText.body1('jobs.empty'.tr()),
|
||||
),
|
||||
if (!jobs.isEmpty) ...[
|
||||
...jobs.jobList
|
||||
.map(
|
||||
(j) => Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: BrandCards.small(
|
||||
child: Row(
|
||||
children: [
|
||||
BrandText.body1(j.title),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
primary: BrandColors.red1,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
onPressed: () =>
|
||||
context.read<JobsCubit>().removeJob(j.id),
|
||||
child: Text('Remove'),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
SizedBox(height: 20),
|
||||
BrandButton.rised(
|
||||
onPressed: () => context.read<JobsCubit>().applyAll(),
|
||||
text: 'jobs.start'.tr(),
|
||||
),
|
||||
],
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
@ -1,13 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
|
||||
class PreStyledButtons {
|
||||
static Widget close({
|
||||
required VoidCallback onPress,
|
||||
}) =>
|
||||
_CloseButton(onPress: onPress);
|
||||
}
|
||||
part of 'pre_styled_buttons.dart';
|
||||
|
||||
class _CloseButton extends StatelessWidget {
|
||||
const _CloseButton({Key? key, required this.onPress}) : super(key: key);
|
@ -0,0 +1,70 @@
|
||||
part of 'pre_styled_buttons.dart';
|
||||
|
||||
class _BrandFlashButton extends StatefulWidget {
|
||||
_BrandFlashButton({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_BrandFlashButtonState createState() => _BrandFlashButtonState();
|
||||
}
|
||||
|
||||
class _BrandFlashButtonState extends State<_BrandFlashButton>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late AnimationController _animationController;
|
||||
late Animation _colorTween;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_animationController =
|
||||
AnimationController(vsync: this, duration: Duration(milliseconds: 600));
|
||||
_colorTween = ColorTween(
|
||||
begin: BrandColors.black,
|
||||
end: BrandColors.primary,
|
||||
).animate(_animationController);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_animationController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
late bool wasPrevStateIsEmpty;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var hasNoJobs = context.watch<JobsCubit>().state.isEmpty;
|
||||
wasPrevStateIsEmpty = hasNoJobs;
|
||||
var icon = hasNoJobs ? Ionicons.flash_outline : Ionicons.flash;
|
||||
|
||||
return BlocListener<JobsCubit, JobsState>(
|
||||
listener: (context, state) {
|
||||
if (wasPrevStateIsEmpty && state.jobList.isNotEmpty) {
|
||||
wasPrevStateIsEmpty = false;
|
||||
_animationController.forward();
|
||||
} else if (!wasPrevStateIsEmpty && state.jobList.isEmpty) {
|
||||
_animationController.reverse();
|
||||
}
|
||||
},
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
showCupertinoModalBottomSheet(
|
||||
expand: false,
|
||||
context: context,
|
||||
builder: (context) => BrandBottomSheet(
|
||||
child: JobsContent(),
|
||||
),
|
||||
);
|
||||
},
|
||||
icon: AnimatedBuilder(
|
||||
animation: _colorTween,
|
||||
builder: (context, child) {
|
||||
return Icon(
|
||||
icon,
|
||||
color: _colorTween.value,
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:ionicons/ionicons.dart';
|
||||
import 'package:selfprivacy/config/brand_colors.dart';
|
||||
import 'package:selfprivacy/logic/cubit/jobs/jobs_cubit.dart';
|
||||
import 'package:selfprivacy/ui/components/brand_bottom_sheet/brand_bottom_sheet.dart';
|
||||
import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
|
||||
import 'package:selfprivacy/ui/components/jobs_content/jobs_content.dart';
|
||||
|
||||
part 'close.dart';
|
||||
part 'flash.dart';
|
||||
|
||||
class PreStyledButtons {
|
||||
static Widget close({
|
||||
required VoidCallback onPress,
|
||||
}) =>
|
||||
_CloseButton(onPress: onPress);
|
||||
|
||||
static Widget flash() => _BrandFlashButton();
|
||||
}
|
Loading…
Reference in New Issue