Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
A
amse
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Matis SPINELLI
amse
Commits
77e2c373
Commit
77e2c373
authored
Feb 10, 2024
by
m-spi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor
parent
d12c9d90
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
288 additions
and
335 deletions
+288
-335
favorite_page.dart
tp1/lib/favorite_page.dart
+50
-49
main.dart
tp1/lib/main.dart
+4
-286
swipe_page.dart
tp1/lib/swipe_page.dart
+234
-0
No files found.
tp1/lib/favorite_page.dart
View file @
77e2c373
...
@@ -4,55 +4,56 @@ import 'app_state.dart';
...
@@ -4,55 +4,56 @@ import 'app_state.dart';
class
FavoritePage
extends
StatelessWidget
{
class
FavoritePage
extends
StatelessWidget
{
@override
Widget
build
(
BuildContext
context
)
{
TindBookState
state
=
Provider
.
of
<
TindBookState
>(
context
);
@override
return
Scaffold
(
Widget
build
(
BuildContext
context
)
{
appBar:
AppBar
(
var
appState
=
context
.
watch
<
TindBookState
>();
title:
Text
(
'Favorite Books'
),
var
favorites
=
appState
.
favorites
;
),
body:
GridView
.
builder
(
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount
(
crossAxisCount:
2
,
childAspectRatio:
0.7
,
),
itemCount:
state
.
favorites
.
length
,
itemBuilder:
(
context
,
index
)
{
return
GestureDetector
(
onTap:
()
{
Navigator
.
push
(
context
,
MaterialPageRoute
(
builder:
(
context
)
=>
ImageScreen
(
imagePath:
state
.
getFav
(
index
)[
'image'
]),
),
);
},
child:
Padding
(
padding:
const
EdgeInsets
.
all
(
8.0
),
child:
Image
.
asset
(
state
.
getFav
(
index
)[
'image'
],
fit:
BoxFit
.
cover
,
),
),
);
},
),
);
}
}
class
ImageScreen
extends
StatelessWidget
{
final
String
imagePath
;
const
ImageScreen
({
Key
?
key
,
required
this
.
imagePath
})
:
super
(
key:
key
);
return
LayoutBuilder
(
builder:
(
context
,
constraints
)
{
@override
return
Scaffold
(
Widget
build
(
BuildContext
context
)
{
backgroundColor:
Colors
.
red
[
200
],
return
Scaffold
(
body:
favorites
.
length
>
0
?
ListView
.
builder
(
appBar:
AppBar
(),
padding:
const
EdgeInsets
.
all
(
8
),
body:
Center
(
itemCount:
favorites
.
length
,
child:
Image
.
asset
(
imagePath
),
itemBuilder:
(
BuildContext
context
,
int
index
){
),
return
ListView
(
);
padding:
const
EdgeInsets
.
all
(
8
),
}
children:
<
Widget
>[
Container
(
color:
index
%
2
==
0
?
Colors
.
red
[
500
]
:
Colors
.
red
[
400
],
child:
Text
(
favorites
[
index
][
'title'
]),
),
Container
(
color:
index
%
2
==
0
?
Colors
.
red
[
500
]
:
Colors
.
red
[
400
],
child:
Text
(
favorites
[
index
][
'subtitle'
]),
),
Container
(
color:
index
%
2
==
0
?
Colors
.
red
[
500
]
:
Colors
.
red
[
400
],
child:
Text
(
favorites
[
index
][
'author'
]),
),
Container
(
color:
index
%
2
==
0
?
Colors
.
red
[
500
]
:
Colors
.
red
[
400
],
child:
Text
(
favorites
[
index
][
'published'
]),
),
Container
(
color:
index
%
2
==
0
?
Colors
.
red
[
500
]
:
Colors
.
red
[
400
],
child:
Text
(
favorites
[
index
][
'publisher'
]),
),
Container
(
color:
index
%
2
==
0
?
Colors
.
red
[
500
]
:
Colors
.
red
[
400
],
child:
Text
(
favorites
[
index
][
'description'
]),
),
Container
(
color:
index
%
2
==
0
?
Colors
.
red
[
500
]
:
Colors
.
red
[
400
],
child:
Text
(
favorites
[
index
][
'website'
]),
)
]
);
}
)
:
Text
(
"No favorites yet !"
),
);
});
}
}
}
tp1/lib/main.dart
View file @
77e2c373
import
'dart:async'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/material.dart'
;
import
'package:provider/provider.dart'
;
import
'package:provider/provider.dart'
;
import
'dart:math'
;
import
'app_state.dart'
;
import
'app_state.dart'
;
import
'favorite_page.dart'
;
import
'swipe_page.dart'
;
void
main
(
)
=>
runApp
(
const
TindBook
());
void
main
(
)
=>
runApp
(
const
TindBook
());
class
TindBook
extends
StatelessWidget
{
class
TindBook
extends
StatelessWidget
{
const
TindBook
({
Key
?
key
})
:
super
(
key:
key
);
const
TindBook
({
Key
?
key
})
:
super
(
key:
key
);
...
@@ -133,287 +135,3 @@ class _MyHomePageState extends State<MyHomePage> {
...
@@ -133,287 +135,3 @@ class _MyHomePageState extends State<MyHomePage> {
);
);
}
}
}
}
class
TindBookContent
extends
StatefulWidget
{
const
TindBookContent
({
Key
?
key
})
:
super
(
key:
key
);
@override
State
<
TindBookContent
>
createState
()
=>
_TindBookContentState
();
}
class
_TindBookContentState
extends
State
<
TindBookContent
>
{
late
TindBookState
state
;
double
_startX
=
0.0
;
double
_currentX
=
0.0
;
double
_deltaX
=
0.0
;
bool
_isSwiping
=
false
;
int
currentImageIndex
=
0
;
@override
void
didChangeDependencies
()
{
super
.
didChangeDependencies
();
state
=
Provider
.
of
<
TindBookState
>(
context
);
}
@override
Widget
build
(
BuildContext
context
)
{
return
LayoutBuilder
(
builder:
(
context
,
constraints
)
{
double
containerWidth
=
constraints
.
maxWidth
;
double
containerHeight
=
constraints
.
maxHeight
;
void
handleSwipe
(
int
direction
)
{
if
(
direction
==
1
)
{
// Swipe right
if
(
currentImageIndex
<
state
.
data
.
length
-
1
)
{
currentImageIndex
++;
state
.
addIndexToFav
(
currentImageIndex
);
}
}
else
{
// Swipe left
if
(
currentImageIndex
>
0
)
{
currentImageIndex
--;
}
}
}
return
GestureDetector
(
onHorizontalDragStart:
(
details
)
{
_startX
=
details
.
globalPosition
.
dx
;
_isSwiping
=
true
;
},
onHorizontalDragUpdate:
(
details
)
{
if
(
_isSwiping
)
{
_currentX
=
details
.
globalPosition
.
dx
;
_deltaX
=
_currentX
-
_startX
;
setState
(()
{});
}
},
onHorizontalDragEnd:
(
details
)
{
if
(
_isSwiping
)
{
_isSwiping
=
false
;
print
(
state
.
data
[
currentImageIndex
][
'image'
]);
if
(
_deltaX
>
50
)
{
handleSwipe
(
1
);
showDialog
(
context:
context
,
builder:
(
_
)
=>
SwipeFeedback
(
isSwipeRight:
true
),
);
}
else
if
(
_deltaX
<
-
50
)
{
handleSwipe
(-
1
);
showDialog
(
context:
context
,
builder:
(
_
)
=>
SwipeFeedback
(
isSwipeRight:
false
),
);
}
}
_startX
=
0.0
;
_currentX
=
0.0
;
_deltaX
=
0.0
;
},
child:
Stack
(
children:
[
Positioned
.
fill
(
child:
Container
(
color:
Color
.
fromRGBO
(
250
,
237
,
205
,
1
),
height:
containerHeight
/
3
,
width:
containerWidth
/
3
,
)),
Positioned
(
top:
20
,
left:
20
,
right:
20
,
bottom:
20
,
child:
Transform
.
translate
(
offset:
Offset
(
_deltaX
,
0.0
),
child:
Transform
.
rotate
(
angle:
_deltaX
*
0.0002
,
// Adjust the rotation speed here
child:
ClipRRect
(
borderRadius:
BorderRadius
.
circular
(
120
),
// Adjust the radius as needed
child:
Image
.
asset
(
state
.
data
[
currentImageIndex
][
'image'
],
height:
containerHeight
/
3
,
// Adjust image height
width:
containerWidth
/
3
,
// Adjust image width
fit:
BoxFit
.
contain
,
),
),
),
),
),
Positioned
(
top:
20
,
left:
20
,
right:
20
,
child:
Container
(
padding:
EdgeInsets
.
all
(
10
),
decoration:
BoxDecoration
(
color:
Colors
.
black
.
withOpacity
(
0.5
),
borderRadius:
BorderRadius
.
circular
(
10
),
boxShadow:
[
BoxShadow
(
color:
Colors
.
black
.
withOpacity
(
0.2
),
blurRadius:
10
,
offset:
Offset
(
0
,
4
),
)],
),
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Text
(
'Titre du livre '
,
style:
TextStyle
(
color:
Colors
.
white
,
fontSize:
20
,
fontWeight:
FontWeight
.
bold
,
),
),
SizedBox
(
height:
5
),
Container
(
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
8
),
),
padding:
EdgeInsets
.
all
(
8
),
child:
Text
(
'un tres bon livre qui parle de beaucoup chose , notamment mais aussi de lorem ipsum dolor sit amet a m Doctrine est pas de '
,
style:
TextStyle
(
color:
Colors
.
black
,
fontSize:
16
,
),
),
),
],
),
),
),
],
),
);
},
);
}
}
class
SwipeFeedback
extends
StatefulWidget
{
final
bool
isSwipeRight
;
const
SwipeFeedback
({
Key
?
key
,
required
this
.
isSwipeRight
})
:
super
(
key:
key
);
@override
_SwipeFeedbackState
createState
()
=>
_SwipeFeedbackState
();
}
class
_SwipeFeedbackState
extends
State
<
SwipeFeedback
>
with
SingleTickerProviderStateMixin
{
late
AnimationController
_controller
;
late
Animation
<
double
>
_animation
;
late
Timer
_timer
;
@override
void
initState
()
{
super
.
initState
();
_controller
=
AnimationController
(
vsync:
this
,
duration:
Duration
(
milliseconds:
200
),
);
_animation
=
Tween
<
double
>(
begin:
0.0
,
end:
1.0
,
).
animate
(
_controller
);
_controller
.
forward
();
_controller
.
addStatusListener
((
status
)
{
if
(
status
==
AnimationStatus
.
completed
)
{
_timer
=
Timer
(
Duration
(
milliseconds:
200
),
()
{
Navigator
.
of
(
context
).
pop
();
// Dismiss the dialog after 500 milliseconds
});
}
else
if
(
status
==
AnimationStatus
.
dismissed
)
{
_controller
.
dispose
();
}
});
}
@override
Widget
build
(
BuildContext
context
)
{
return
Center
(
child:
AnimatedBuilder
(
animation:
_animation
,
builder:
(
context
,
child
)
{
return
Opacity
(
opacity:
1.0
-
_animation
.
value
,
child:
Transform
.
scale
(
scale:
1.0
+
_animation
.
value
*
0.5
,
child:
Icon
(
widget
.
isSwipeRight
?
Icons
.
favorite
:
Icons
.
close
,
color:
widget
.
isSwipeRight
?
Colors
.
green
:
Colors
.
red
,
size:
400.0
,
),
),
);
},
),
);
}
@override
void
dispose
()
{
_controller
.
dispose
();
_timer
.
cancel
();
// Cancel the timer when disposing the widget
super
.
dispose
();
}
}
class
FavoritePage
extends
StatelessWidget
{
@override
Widget
build
(
BuildContext
context
)
{
TindBookState
state
=
Provider
.
of
<
TindBookState
>(
context
);
return
Scaffold
(
appBar:
AppBar
(
title:
Text
(
'Favorite Books'
),
),
body:
GridView
.
builder
(
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount
(
crossAxisCount:
2
,
childAspectRatio:
0.7
,
),
itemCount:
state
.
favorites
.
length
,
itemBuilder:
(
context
,
index
)
{
return
GestureDetector
(
onTap:
()
{
Navigator
.
push
(
context
,
MaterialPageRoute
(
builder:
(
context
)
=>
ImageScreen
(
imagePath:
state
.
getFav
(
index
)[
'image'
]),
),
);
},
child:
Padding
(
padding:
const
EdgeInsets
.
all
(
8.0
),
child:
Image
.
asset
(
state
.
getFav
(
index
)[
'image'
],
fit:
BoxFit
.
cover
,
),
),
);
},
),
);
}
}
class
ImageScreen
extends
StatelessWidget
{
final
String
imagePath
;
const
ImageScreen
({
Key
?
key
,
required
this
.
imagePath
})
:
super
(
key:
key
);
@override
Widget
build
(
BuildContext
context
)
{
return
Scaffold
(
appBar:
AppBar
(),
body:
Center
(
child:
Image
.
asset
(
imagePath
),
),
);
}
}
tp1/lib/swipe_page.dart
0 → 100644
View file @
77e2c373
import
'dart:async'
;
import
'package:flutter/material.dart'
;
import
'package:provider/provider.dart'
;
import
'app_state.dart'
;
class
TindBookContent
extends
StatefulWidget
{
const
TindBookContent
({
Key
?
key
})
:
super
(
key:
key
);
@override
State
<
TindBookContent
>
createState
()
=>
_TindBookContentState
();
}
class
_TindBookContentState
extends
State
<
TindBookContent
>
{
late
TindBookState
state
;
double
_startX
=
0.0
;
double
_currentX
=
0.0
;
double
_deltaX
=
0.0
;
bool
_isSwiping
=
false
;
int
currentImageIndex
=
0
;
@override
void
didChangeDependencies
()
{
super
.
didChangeDependencies
();
state
=
Provider
.
of
<
TindBookState
>(
context
);
}
@override
Widget
build
(
BuildContext
context
)
{
return
LayoutBuilder
(
builder:
(
context
,
constraints
)
{
double
containerWidth
=
constraints
.
maxWidth
;
double
containerHeight
=
constraints
.
maxHeight
;
void
handleSwipe
(
int
direction
)
{
if
(
direction
==
1
)
{
// Swipe right
if
(
currentImageIndex
<
state
.
data
.
length
-
1
)
{
currentImageIndex
++;
state
.
addIndexToFav
(
currentImageIndex
);
}
}
else
{
// Swipe left
if
(
currentImageIndex
>
0
)
{
currentImageIndex
--;
}
}
}
return
GestureDetector
(
onHorizontalDragStart:
(
details
)
{
_startX
=
details
.
globalPosition
.
dx
;
_isSwiping
=
true
;
},
onHorizontalDragUpdate:
(
details
)
{
if
(
_isSwiping
)
{
_currentX
=
details
.
globalPosition
.
dx
;
_deltaX
=
_currentX
-
_startX
;
setState
(()
{});
}
},
onHorizontalDragEnd:
(
details
)
{
if
(
_isSwiping
)
{
_isSwiping
=
false
;
print
(
state
.
data
[
currentImageIndex
][
'image'
]);
if
(
_deltaX
>
50
)
{
handleSwipe
(
1
);
showDialog
(
context:
context
,
builder:
(
_
)
=>
SwipeFeedback
(
isSwipeRight:
true
),
);
}
else
if
(
_deltaX
<
-
50
)
{
handleSwipe
(-
1
);
showDialog
(
context:
context
,
builder:
(
_
)
=>
SwipeFeedback
(
isSwipeRight:
false
),
);
}
}
_startX
=
0.0
;
_currentX
=
0.0
;
_deltaX
=
0.0
;
},
child:
Stack
(
children:
[
Positioned
.
fill
(
child:
Container
(
color:
Color
.
fromRGBO
(
250
,
237
,
205
,
1
),
height:
containerHeight
/
3
,
width:
containerWidth
/
3
,
)),
Positioned
(
top:
20
,
left:
20
,
right:
20
,
bottom:
20
,
child:
Transform
.
translate
(
offset:
Offset
(
_deltaX
,
0.0
),
child:
Transform
.
rotate
(
angle:
_deltaX
*
0.0002
,
// Adjust the rotation speed here
child:
ClipRRect
(
borderRadius:
BorderRadius
.
circular
(
120
),
// Adjust the radius as needed
child:
Image
.
asset
(
state
.
data
[
currentImageIndex
][
'image'
],
height:
containerHeight
/
3
,
// Adjust image height
width:
containerWidth
/
3
,
// Adjust image width
fit:
BoxFit
.
contain
,
),
),
),
),
),
Positioned
(
top:
20
,
left:
20
,
right:
20
,
child:
Container
(
padding:
EdgeInsets
.
all
(
10
),
decoration:
BoxDecoration
(
color:
Colors
.
black
.
withOpacity
(
0.5
),
borderRadius:
BorderRadius
.
circular
(
10
),
boxShadow:
[
BoxShadow
(
color:
Colors
.
black
.
withOpacity
(
0.2
),
blurRadius:
10
,
offset:
Offset
(
0
,
4
),
)],
),
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Text
(
'Titre du livre '
,
style:
TextStyle
(
color:
Colors
.
white
,
fontSize:
20
,
fontWeight:
FontWeight
.
bold
,
),
),
SizedBox
(
height:
5
),
Container
(
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
8
),
),
padding:
EdgeInsets
.
all
(
8
),
child:
Text
(
'un tres bon livre qui parle de beaucoup chose , notamment mais aussi de lorem ipsum dolor sit amet a m Doctrine est pas de '
,
style:
TextStyle
(
color:
Colors
.
black
,
fontSize:
16
,
),
),
),
],
),
),
),
],
),
);
},
);
}
}
class
SwipeFeedback
extends
StatefulWidget
{
final
bool
isSwipeRight
;
const
SwipeFeedback
({
Key
?
key
,
required
this
.
isSwipeRight
})
:
super
(
key:
key
);
@override
_SwipeFeedbackState
createState
()
=>
_SwipeFeedbackState
();
}
class
_SwipeFeedbackState
extends
State
<
SwipeFeedback
>
with
SingleTickerProviderStateMixin
{
late
AnimationController
_controller
;
late
Animation
<
double
>
_animation
;
late
Timer
_timer
;
@override
void
initState
()
{
super
.
initState
();
_controller
=
AnimationController
(
vsync:
this
,
duration:
Duration
(
milliseconds:
200
),
);
_animation
=
Tween
<
double
>(
begin:
0.0
,
end:
1.0
,
).
animate
(
_controller
);
_controller
.
forward
();
_controller
.
addStatusListener
((
status
)
{
if
(
status
==
AnimationStatus
.
completed
)
{
_timer
=
Timer
(
Duration
(
milliseconds:
200
),
()
{
Navigator
.
of
(
context
).
pop
();
// Dismiss the dialog after 500 milliseconds
});
}
else
if
(
status
==
AnimationStatus
.
dismissed
)
{
_controller
.
dispose
();
}
});
}
@override
Widget
build
(
BuildContext
context
)
{
return
Center
(
child:
AnimatedBuilder
(
animation:
_animation
,
builder:
(
context
,
child
)
{
return
Opacity
(
opacity:
1.0
-
_animation
.
value
,
child:
Transform
.
scale
(
scale:
1.0
+
_animation
.
value
*
0.5
,
child:
Icon
(
widget
.
isSwipeRight
?
Icons
.
favorite
:
Icons
.
close
,
color:
widget
.
isSwipeRight
?
Colors
.
green
:
Colors
.
red
,
size:
400.0
,
),
),
);
},
),
);
}
@override
void
dispose
()
{
_controller
.
dispose
();
_timer
.
cancel
();
// Cancel the timer when disposing the widget
super
.
dispose
();
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment