After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 816 B |
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 1.1 MiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 223 B |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 4.8 KiB |
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 230 B |
@ -0,0 +1,34 @@
|
|||||||
|
import 'package:flutter/Material.dart';
|
||||||
|
|
||||||
|
import '../values/constants.dart';
|
||||||
|
|
||||||
|
class BackButtonComponent extends StatefulWidget {
|
||||||
|
const BackButtonComponent({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<BackButtonComponent> createState() => _BackButtonComponentState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _BackButtonComponentState extends State<BackButtonComponent> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
child: ClipOval(
|
||||||
|
child: Container(
|
||||||
|
height: 40,
|
||||||
|
width: 40,
|
||||||
|
color: Colors.white,
|
||||||
|
child: Center(
|
||||||
|
child: Icon(
|
||||||
|
Icons.arrow_back_outlined,
|
||||||
|
color: bgColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,113 @@
|
|||||||
|
import 'package:auto_size_text/auto_size_text.dart';
|
||||||
|
import 'package:flutter/Material.dart';
|
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:justmusic/values/constants.dart';
|
||||||
|
|
||||||
|
class EditablePostComponent extends StatefulWidget {
|
||||||
|
const EditablePostComponent({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<EditablePostComponent> createState() => _EditablePostComponentState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _EditablePostComponentState extends State<EditablePostComponent> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(25),
|
||||||
|
child: Container(
|
||||||
|
constraints: BoxConstraints(maxWidth: 400),
|
||||||
|
width: double.infinity,
|
||||||
|
color: warningBttnColor,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
AspectRatio(
|
||||||
|
aspectRatio: 1 / 1,
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
// add border
|
||||||
|
border: Border.all(width: 3.0, color: grayColor),
|
||||||
|
// set border radius
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
),
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(18),
|
||||||
|
// implement image
|
||||||
|
child: const Image(
|
||||||
|
image: AssetImage("assets/images/exemple_cover.png"),
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
width: double.infinity,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(15, 25, 15, 25),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
AutoSizeText(
|
||||||
|
"France, Lyon",
|
||||||
|
style: GoogleFonts.plusJakartaSans(
|
||||||
|
color: Colors.white, fontSize: 13.sp),
|
||||||
|
maxFontSize: 20,
|
||||||
|
),
|
||||||
|
Image(
|
||||||
|
image: AssetImage("assets/images/camera_icon.png"),
|
||||||
|
width: 30,
|
||||||
|
),
|
||||||
|
AutoSizeText(
|
||||||
|
"10 Juil. 2023",
|
||||||
|
style: GoogleFonts.plusJakartaSans(
|
||||||
|
color: Colors.white, fontSize: 13.sp),
|
||||||
|
maxFontSize: 20,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(15, 0, 10, 25),
|
||||||
|
child: SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: TextFormField(
|
||||||
|
keyboardAppearance: Brightness.dark,
|
||||||
|
minLines: 1,
|
||||||
|
cursorColor: primaryColor,
|
||||||
|
style: GoogleFonts.plusJakartaSans(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 13,
|
||||||
|
fontWeight: FontWeight.w300),
|
||||||
|
maxLines: 4,
|
||||||
|
maxLength: 120,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
counterStyle: GoogleFonts.plusJakartaSans(
|
||||||
|
color: grayText, fontSize: 9),
|
||||||
|
focusedBorder: const OutlineInputBorder(
|
||||||
|
borderSide:
|
||||||
|
BorderSide(width: 0, color: Colors.transparent),
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.all(Radius.circular(10))),
|
||||||
|
contentPadding:
|
||||||
|
const EdgeInsets.only(top: 0, bottom: 0, left: 0),
|
||||||
|
fillColor: Colors.transparent,
|
||||||
|
filled: true,
|
||||||
|
focusColor: Colors.transparent,
|
||||||
|
enabledBorder: const OutlineInputBorder(
|
||||||
|
borderSide:
|
||||||
|
BorderSide(width: 0, color: Colors.transparent),
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.all(Radius.circular(10))),
|
||||||
|
hintText: 'Description...',
|
||||||
|
hintStyle: GoogleFonts.plusJakartaSans(
|
||||||
|
color: grayText,
|
||||||
|
fontSize: 13,
|
||||||
|
fontWeight: FontWeight.w300),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,100 @@
|
|||||||
|
import 'package:flutter/Material.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:justmusic/components/play_button_component.dart';
|
||||||
|
import 'package:text_scroll/text_scroll.dart';
|
||||||
|
import '../model/Music.dart';
|
||||||
|
|
||||||
|
class MusicListComponent extends StatelessWidget {
|
||||||
|
final Music music;
|
||||||
|
const MusicListComponent({
|
||||||
|
Key? key,
|
||||||
|
required this.music,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.only(bottom: 14),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
LayoutBuilder(
|
||||||
|
builder: (BuildContext context, BoxConstraints constraints) {
|
||||||
|
if (music.cover != null) {
|
||||||
|
return ClipRRect(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(5)),
|
||||||
|
child: music.cover != null
|
||||||
|
? FadeInImage.assetNetwork(
|
||||||
|
height: 60,
|
||||||
|
width: 60,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
placeholder: "assets/images/loadingPlaceholder.gif",
|
||||||
|
image: music.cover!)
|
||||||
|
: Container(
|
||||||
|
height: 60,
|
||||||
|
width: 60,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Image(
|
||||||
|
image: AssetImage("assets/images/exemple_cover.png"),
|
||||||
|
height: 60,
|
||||||
|
width: 60,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
const SizedBox(
|
||||||
|
width: 10,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 10,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Flexible(
|
||||||
|
flex: 8,
|
||||||
|
child: ScrollConfiguration(
|
||||||
|
behavior:
|
||||||
|
ScrollBehavior().copyWith(scrollbars: false),
|
||||||
|
child: TextScroll(
|
||||||
|
music.title ?? "Unknown",
|
||||||
|
style: GoogleFonts.plusJakartaSans(
|
||||||
|
fontSize: 16,
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.w700),
|
||||||
|
mode: TextScrollMode.endless,
|
||||||
|
pauseBetween: Duration(milliseconds: 2500),
|
||||||
|
velocity: Velocity(pixelsPerSecond: Offset(30, 0)),
|
||||||
|
intervalSpaces: 10,
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
Icon(
|
||||||
|
Icons.explicit,
|
||||||
|
color: Colors.grey.withOpacity(0.7),
|
||||||
|
size: 17,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
ScrollConfiguration(
|
||||||
|
behavior: ScrollBehavior().copyWith(scrollbars: false),
|
||||||
|
child: Text(
|
||||||
|
music.artists.first.name ?? "Unknown",
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: GoogleFonts.plusJakartaSans(
|
||||||
|
color: Colors.grey, fontWeight: FontWeight.w400),
|
||||||
|
))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Spacer(),
|
||||||
|
PlayButtonComponent(
|
||||||
|
urlPreview: music.previewUrl,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
import 'package:audioplayers/audioplayers.dart';
|
||||||
|
import 'package:flutter/Material.dart';
|
||||||
|
import 'package:flutter_animated_play_button/flutter_animated_play_button.dart';
|
||||||
|
import 'package:ionicons/ionicons.dart';
|
||||||
|
|
||||||
|
class PlayButtonComponent extends StatefulWidget {
|
||||||
|
final String? urlPreview;
|
||||||
|
const PlayButtonComponent({Key? key, required this.urlPreview})
|
||||||
|
: super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<PlayButtonComponent> createState() => _PlayButtonComponentState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PlayButtonComponentState extends State<PlayButtonComponent> {
|
||||||
|
bool isPlaying = true;
|
||||||
|
final player = AudioPlayer();
|
||||||
|
void switchStatePlaying() {
|
||||||
|
setState(() {
|
||||||
|
isPlaying = !isPlaying;
|
||||||
|
});
|
||||||
|
stopSong();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
player.onPlayerComplete.listen((event) {
|
||||||
|
switchStatePlaying();
|
||||||
|
});
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (!isPlaying) {
|
||||||
|
playSong();
|
||||||
|
} else {}
|
||||||
|
return isPlaying
|
||||||
|
? GestureDetector(
|
||||||
|
onTap: switchStatePlaying,
|
||||||
|
child: Container(
|
||||||
|
width: 30,
|
||||||
|
height: 30,
|
||||||
|
child: Icon(
|
||||||
|
Ionicons.play_circle_outline,
|
||||||
|
color: Colors.grey.withOpacity(0.3),
|
||||||
|
size: 30,
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
: GestureDetector(
|
||||||
|
onTap: switchStatePlaying,
|
||||||
|
child: Container(
|
||||||
|
width: 30,
|
||||||
|
height: 30,
|
||||||
|
child: AnimatedPlayButton(
|
||||||
|
stopped: false,
|
||||||
|
color: Colors.grey.withOpacity(0.3),
|
||||||
|
onPressed: () {},
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> playSong() async {
|
||||||
|
if (widget.urlPreview != null) {
|
||||||
|
await player.play(UrlSource(widget.urlPreview ?? ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> stopSong() async {
|
||||||
|
await player.stop();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
import 'package:flutter/Material.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
|
|
||||||
|
class PostButtonComponent extends StatelessWidget {
|
||||||
|
const PostButtonComponent({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
constraints: BoxConstraints(maxWidth: 400),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: LinearGradient(colors: [
|
||||||
|
Color(0xFF141414),
|
||||||
|
Color(0xFF272727),
|
||||||
|
Color(0xFF141414)
|
||||||
|
]),
|
||||||
|
borderRadius: BorderRadius.circular(10000)),
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 25),
|
||||||
|
width: double.infinity,
|
||||||
|
child: Align(
|
||||||
|
child: Text(
|
||||||
|
"Publier la capsule",
|
||||||
|
style: GoogleFonts.plusJakartaSans(
|
||||||
|
color: Color(0xFF474747),
|
||||||
|
fontWeight: FontWeight.w800,
|
||||||
|
fontStyle: FontStyle.italic,
|
||||||
|
fontSize: 24),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
import 'package:auto_size_text/auto_size_text.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:justmusic/components/statistics_component.dart';
|
||||||
|
|
||||||
|
import '../model/User.dart';
|
||||||
|
|
||||||
|
class ProfileComponent extends StatelessWidget {
|
||||||
|
final User user;
|
||||||
|
const ProfileComponent({Key? key, required this.user}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
ClipOval(
|
||||||
|
child: ConstrainedBox(
|
||||||
|
constraints: BoxConstraints(maxWidth: 200, maxHeight: 200),
|
||||||
|
child: Image(
|
||||||
|
image: AssetImage("assets/images/exemple_profile.png"),
|
||||||
|
height: 100.w,
|
||||||
|
width: 100.w,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 10,
|
||||||
|
),
|
||||||
|
AutoSizeText(
|
||||||
|
"@${user.pseudo}",
|
||||||
|
style: GoogleFonts.plusJakartaSans(
|
||||||
|
fontSize: 15.sp,
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.w400),
|
||||||
|
maxFontSize: 30,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 20,
|
||||||
|
),
|
||||||
|
StatisticsComponent(
|
||||||
|
user: user,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
import 'package:flutter/Material.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
|
||||||
|
import '../values/constants.dart';
|
||||||
|
|
||||||
|
class SearchBarComponent extends StatefulWidget {
|
||||||
|
final String? text;
|
||||||
|
final VoidCallback? callback;
|
||||||
|
const SearchBarComponent({Key? key, this.text, this.callback})
|
||||||
|
: super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<SearchBarComponent> createState() => _SearchBarComponentState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SearchBarComponentState extends State<SearchBarComponent> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: widget.callback,
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(20)),
|
||||||
|
child: Container(
|
||||||
|
constraints: BoxConstraints(maxWidth: 600),
|
||||||
|
color: searchBarColor,
|
||||||
|
width: double.infinity,
|
||||||
|
padding: EdgeInsets.fromLTRB(defaultPadding, 16, defaultPadding, 16),
|
||||||
|
child: Text(
|
||||||
|
widget.text ?? "Chercher une musique...",
|
||||||
|
style: GoogleFonts.plusJakartaSans(color: Colors.white),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:justmusic/values/icons.dart';
|
||||||
|
|
||||||
|
import '../values/constants.dart';
|
||||||
|
|
||||||
|
class SettingPartComponent extends StatelessWidget {
|
||||||
|
final JustMusicIcon icon;
|
||||||
|
final String label;
|
||||||
|
final bool important;
|
||||||
|
const SettingPartComponent(
|
||||||
|
{Key? key,
|
||||||
|
required this.icon,
|
||||||
|
required this.label,
|
||||||
|
this.important = false})
|
||||||
|
: super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Material(
|
||||||
|
color: important ? warningBttnColor : settingColor,
|
||||||
|
borderOnForeground: false,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () {
|
||||||
|
print('InkWell was tapped!');
|
||||||
|
},
|
||||||
|
splashColor: Colors.transparent,
|
||||||
|
highlightColor: Colors.white.withOpacity(0.08),
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(
|
||||||
|
defaultPadding, 19, defaultPadding, 19),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Image(
|
||||||
|
image: AssetImage(icon.imagePath),
|
||||||
|
width: 13,
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 15,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 10,
|
||||||
|
child: Text(
|
||||||
|
label,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: GoogleFonts.plusJakartaSans(
|
||||||
|
color: Colors.white, fontWeight: FontWeight.w700),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Spacer(),
|
||||||
|
Transform(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
transform: Matrix4.rotationY(3.14159265),
|
||||||
|
child: Image(
|
||||||
|
image: AssetImage("assets/images/return_icon.png"),
|
||||||
|
height: 11,
|
||||||
|
opacity: const AlwaysStoppedAnimation(.5),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
import 'package:auto_size_text/auto_size_text.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
|
||||||
|
import '../model/User.dart';
|
||||||
|
import '../values/constants.dart';
|
||||||
|
|
||||||
|
class StatisticsComponent extends StatelessWidget {
|
||||||
|
final User user;
|
||||||
|
const StatisticsComponent({Key? key, required this.user}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
AutoSizeText(
|
||||||
|
user.followed.toString(),
|
||||||
|
style: GoogleFonts.plusJakartaSans(
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 15.w),
|
||||||
|
maxFontSize: 30,
|
||||||
|
),
|
||||||
|
AutoSizeText(
|
||||||
|
"Suivis",
|
||||||
|
style: GoogleFonts.plusJakartaSans(
|
||||||
|
color: grayText, fontSize: 12.w),
|
||||||
|
maxFontSize: 30,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
AutoSizeText(
|
||||||
|
user.followers.toString(),
|
||||||
|
style: GoogleFonts.plusJakartaSans(
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 15.w),
|
||||||
|
maxFontSize: 30,
|
||||||
|
),
|
||||||
|
AutoSizeText(
|
||||||
|
"Followers",
|
||||||
|
style:
|
||||||
|
GoogleFonts.plusJakartaSans(color: grayText, fontSize: 12.w),
|
||||||
|
maxFontSize: 30,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
AutoSizeText(
|
||||||
|
user.capsules.toString(),
|
||||||
|
style: GoogleFonts.plusJakartaSans(
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 15.w),
|
||||||
|
maxFontSize: 30,
|
||||||
|
),
|
||||||
|
AutoSizeText(
|
||||||
|
"Capsules",
|
||||||
|
style: GoogleFonts.plusJakartaSans(
|
||||||
|
color: grayText, fontSize: 12.w),
|
||||||
|
maxFontSize: 30,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
import 'package:flutter/Material.dart';
|
||||||
|
import 'package:justmusic/screens/profile_screen.dart';
|
||||||
|
|
||||||
|
Route createRoute() {
|
||||||
|
return PageRouteBuilder(
|
||||||
|
pageBuilder: (context, animation, secondaryAnimation) =>
|
||||||
|
const ProfileScreen(),
|
||||||
|
transitionsBuilder: (context, animation, secondaryAnimation, child) {
|
||||||
|
const begin = Offset(1.0, 0.0);
|
||||||
|
const end = Offset.zero;
|
||||||
|
const curve = Curves.ease;
|
||||||
|
|
||||||
|
var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
|
||||||
|
|
||||||
|
return SlideTransition(
|
||||||
|
position: animation.drive(tween),
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,126 @@
|
|||||||
|
import 'dart:ui';
|
||||||
|
import 'package:flutter/Material.dart';
|
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
|
import 'package:justmusic/components/back_button.dart';
|
||||||
|
import 'package:justmusic/screens/search_song_screen.dart';
|
||||||
|
import '../components/editable_post_component.dart';
|
||||||
|
import '../components/post_button_component.dart';
|
||||||
|
import '../values/constants.dart';
|
||||||
|
|
||||||
|
class PostScreen extends StatefulWidget {
|
||||||
|
const PostScreen({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<PostScreen> createState() => _PostScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PostScreenState extends State<PostScreen>
|
||||||
|
with SingleTickerProviderStateMixin {
|
||||||
|
final scrollController = ScrollController();
|
||||||
|
late AnimationController _controller;
|
||||||
|
late Animation<double> _animation;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
_controller = AnimationController(
|
||||||
|
vsync: this,
|
||||||
|
duration: const Duration(milliseconds: 400),
|
||||||
|
);
|
||||||
|
|
||||||
|
_animation = Tween<double>(begin: 0.0, end: 400.0).animate(
|
||||||
|
CurvedAnimation(
|
||||||
|
parent: _controller,
|
||||||
|
curve: Curves.easeOut,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void openDetailPost() {
|
||||||
|
showModalBottomSheet(
|
||||||
|
transitionAnimationController: _controller,
|
||||||
|
barrierColor: Colors.black.withOpacity(0.7),
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
elevation: 1,
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
maxWidth: 600,
|
||||||
|
),
|
||||||
|
isScrollControlled: true,
|
||||||
|
context: context,
|
||||||
|
shape: const RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(20), topRight: Radius.circular(20))),
|
||||||
|
builder: ((context) {
|
||||||
|
return const ClipRRect(
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(20), topRight: Radius.circular(20)),
|
||||||
|
child: SearchSongScreen());
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
resizeToAvoidBottomInset: true,
|
||||||
|
backgroundColor: bgColor,
|
||||||
|
extendBodyBehindAppBar: true,
|
||||||
|
appBar: PreferredSize(
|
||||||
|
preferredSize: Size(double.infinity, 80),
|
||||||
|
child: SafeArea(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
left: defaultPadding,
|
||||||
|
right: defaultPadding,
|
||||||
|
top: defaultPadding),
|
||||||
|
child: Row(
|
||||||
|
children: [BackButtonComponent()],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: Container(
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.only(left: defaultPadding, right: defaultPadding),
|
||||||
|
width: double.infinity,
|
||||||
|
height: double.infinity,
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
image: DecorationImage(
|
||||||
|
image: AssetImage("assets/images/background_justMusic.png"),
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Stack(
|
||||||
|
alignment: Alignment.topCenter,
|
||||||
|
children: [
|
||||||
|
ScrollConfiguration(
|
||||||
|
behavior: ScrollBehavior().copyWith(scrollbars: false),
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
controller: scrollController,
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: 100.h,
|
||||||
|
),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: openDetailPost,
|
||||||
|
child: EditablePostComponent(),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 40.h,
|
||||||
|
),
|
||||||
|
PostButtonComponent(),
|
||||||
|
SizedBox(
|
||||||
|
height: 40.h,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,146 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:justmusic/values/icons.dart';
|
||||||
|
import '../components/profile_component.dart';
|
||||||
|
import '../components/setting_part_component.dart';
|
||||||
|
import '../main.dart';
|
||||||
|
import '../values/constants.dart';
|
||||||
|
|
||||||
|
class ProfileScreen extends StatefulWidget {
|
||||||
|
const ProfileScreen({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ProfileScreen> createState() => _ProfileScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ProfileScreenState extends State<ProfileScreen> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: PreferredSize(
|
||||||
|
preferredSize: Size(double.infinity, 58),
|
||||||
|
child: Container(
|
||||||
|
height: double.infinity,
|
||||||
|
color: bgAppBar,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: defaultPadding),
|
||||||
|
child: Stack(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
children: [
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
height: 15,
|
||||||
|
width: 15,
|
||||||
|
child: Image(
|
||||||
|
image: AssetImage("assets/images/return_icon.png"),
|
||||||
|
height: 8,
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
Align(
|
||||||
|
child: Text(
|
||||||
|
"Profile",
|
||||||
|
style: GoogleFonts.plusJakartaSans(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: double.infinity,
|
||||||
|
color: bgColor,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: settingPadding),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(top: 68.h, bottom: 40),
|
||||||
|
child:
|
||||||
|
ProfileComponent(user: MyApp.userViewModel.userCurrent),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.only(bottom: 12, left: defaultPadding),
|
||||||
|
child: Text(
|
||||||
|
"Compte",
|
||||||
|
style: GoogleFonts.plusJakartaSans(
|
||||||
|
color: grayText,
|
||||||
|
fontWeight: FontWeight.w800,
|
||||||
|
fontSize: 16),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
child: Column(
|
||||||
|
children: const [
|
||||||
|
SettingPartComponent(
|
||||||
|
icon: JustMusicIcon.profile,
|
||||||
|
label: 'Compte',
|
||||||
|
),
|
||||||
|
SettingPartComponent(
|
||||||
|
icon: JustMusicIcon.history,
|
||||||
|
label: 'Historiques des capsules',
|
||||||
|
),
|
||||||
|
SettingPartComponent(
|
||||||
|
icon: JustMusicIcon.spotify,
|
||||||
|
label: 'Lier un compte Spotify',
|
||||||
|
),
|
||||||
|
SettingPartComponent(
|
||||||
|
icon: JustMusicIcon.trash,
|
||||||
|
label: 'Supprimer mon compte',
|
||||||
|
),
|
||||||
|
SettingPartComponent(
|
||||||
|
icon: JustMusicIcon.cross,
|
||||||
|
label: 'Déconnexion',
|
||||||
|
important: true,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
bottom: 12, left: defaultPadding, top: 40),
|
||||||
|
child: Text(
|
||||||
|
"Préférences",
|
||||||
|
style: GoogleFonts.plusJakartaSans(
|
||||||
|
color: grayText,
|
||||||
|
fontWeight: FontWeight.w800,
|
||||||
|
fontSize: 16),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
child: Column(
|
||||||
|
children: const [
|
||||||
|
SettingPartComponent(
|
||||||
|
icon: JustMusicIcon.theme,
|
||||||
|
label: 'Thême de l\'application',
|
||||||
|
),
|
||||||
|
SettingPartComponent(
|
||||||
|
icon: JustMusicIcon.notification,
|
||||||
|
label: 'Notifications',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,169 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
|
import 'package:flutter/Material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:justmusic/model/Music.dart';
|
||||||
|
|
||||||
|
import '../components/music_list_component.dart';
|
||||||
|
import '../values/constants.dart';
|
||||||
|
import '../main.dart';
|
||||||
|
|
||||||
|
class SearchSongScreen extends StatefulWidget {
|
||||||
|
const SearchSongScreen({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<SearchSongScreen> createState() => _SearchSongScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SearchSongScreenState extends State<SearchSongScreen> {
|
||||||
|
final ScrollController _scrollController = ScrollController();
|
||||||
|
final TextEditingController _textEditingController = TextEditingController();
|
||||||
|
|
||||||
|
Future<void> resetFullScreen() async {
|
||||||
|
await SystemChannels.platform.invokeMethod<void>(
|
||||||
|
'SystemChrome.restoreSystemUIOverlays',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_scrollController.addListener(_scrollListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _scrollListener() async {
|
||||||
|
if (_scrollController.position.pixels ==
|
||||||
|
_scrollController.position.maxScrollExtent) {
|
||||||
|
filteredData.addAll(await MyApp.musicViewModel.getMusicsWithName(
|
||||||
|
_textEditingController.text,
|
||||||
|
limit: 10,
|
||||||
|
offset: filteredData.length));
|
||||||
|
setState(() {
|
||||||
|
filteredData = filteredData;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (_scrollController.offset >=
|
||||||
|
_scrollController.position.maxScrollExtent &&
|
||||||
|
!_scrollController.position.outOfRange) {
|
||||||
|
setState(() {
|
||||||
|
//you can do anything here
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (_scrollController.offset <=
|
||||||
|
_scrollController.position.minScrollExtent &&
|
||||||
|
!_scrollController.position.outOfRange) {
|
||||||
|
setState(() {
|
||||||
|
Timer(Duration(milliseconds: 1), () => _scrollController.jumpTo(0));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Music> filteredData = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
double screenHeight = MediaQuery.of(context).size.height;
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
FocusScopeNode currentFocus = FocusScope.of(context);
|
||||||
|
if (!currentFocus.hasPrimaryFocus) {
|
||||||
|
currentFocus.unfocus();
|
||||||
|
resetFullScreen();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: BackdropFilter(
|
||||||
|
filter: ImageFilter.blur(
|
||||||
|
sigmaX: 60.0,
|
||||||
|
sigmaY: 60.0,
|
||||||
|
),
|
||||||
|
child: Container(
|
||||||
|
color: bgAppBar.withOpacity(0.5),
|
||||||
|
height: screenHeight - 50,
|
||||||
|
padding: const EdgeInsets.only(top: 10),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Align(
|
||||||
|
child: Container(
|
||||||
|
width: 60,
|
||||||
|
height: 5,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Color(0xFF3A3A3A).withOpacity(0.6),
|
||||||
|
borderRadius: BorderRadius.circular(20))),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 10,
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.only(bottom: 10, left: 20, right: 20),
|
||||||
|
child: SizedBox(
|
||||||
|
height: 40,
|
||||||
|
child: TextField(
|
||||||
|
controller: _textEditingController,
|
||||||
|
keyboardAppearance: Brightness.dark,
|
||||||
|
onEditingComplete: resetFullScreen,
|
||||||
|
onChanged: (value) async {
|
||||||
|
if (_textEditingController.text.isEmpty) {
|
||||||
|
} else if (value == " ") {
|
||||||
|
print("popular");
|
||||||
|
} else {
|
||||||
|
filteredData = await MyApp.musicViewModel
|
||||||
|
.getMusicsWithName(value);
|
||||||
|
setState(() {
|
||||||
|
filteredData = filteredData;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
cursorColor: Colors.white,
|
||||||
|
keyboardType: TextInputType.text,
|
||||||
|
style: GoogleFonts.plusJakartaSans(color: grayText),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
prefixIcon: const Icon(
|
||||||
|
Icons.search,
|
||||||
|
color: grayColor,
|
||||||
|
),
|
||||||
|
focusedBorder: const OutlineInputBorder(
|
||||||
|
borderSide:
|
||||||
|
BorderSide(width: 1, color: grayColor),
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.all(Radius.circular(10))),
|
||||||
|
contentPadding: const EdgeInsets.only(
|
||||||
|
top: 0,
|
||||||
|
bottom: 0,
|
||||||
|
left: defaultPadding,
|
||||||
|
right: defaultPadding),
|
||||||
|
fillColor: searchBarColor,
|
||||||
|
filled: true,
|
||||||
|
focusColor: grayText,
|
||||||
|
enabledBorder: const OutlineInputBorder(
|
||||||
|
borderSide:
|
||||||
|
BorderSide(width: 1, color: grayColor),
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.all(Radius.circular(10))),
|
||||||
|
hintText: 'Chercher un son',
|
||||||
|
hintStyle:
|
||||||
|
GoogleFonts.plusJakartaSans(color: grayColor)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Flexible(
|
||||||
|
child: ScrollConfiguration(
|
||||||
|
behavior: ScrollBehavior().copyWith(scrollbars: true),
|
||||||
|
child: ListView.builder(
|
||||||
|
controller: _scrollController,
|
||||||
|
itemCount: filteredData.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
|
child: MusicListComponent(music: filteredData[index]),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
enum JustMusicIcon {
|
||||||
|
profile,
|
||||||
|
spotify,
|
||||||
|
trash,
|
||||||
|
cross,
|
||||||
|
history,
|
||||||
|
theme,
|
||||||
|
notification
|
||||||
|
}
|
||||||
|
|
||||||
|
extension MyIconExtension on JustMusicIcon {
|
||||||
|
String get imagePath {
|
||||||
|
switch (this) {
|
||||||
|
case JustMusicIcon.profile:
|
||||||
|
return 'assets/images/profile_icon.png';
|
||||||
|
case JustMusicIcon.spotify:
|
||||||
|
return 'assets/images/spotify_icon.png';
|
||||||
|
case JustMusicIcon.trash:
|
||||||
|
return 'assets/images/trash_icon.png';
|
||||||
|
case JustMusicIcon.cross:
|
||||||
|
return 'assets/images/cross_icon.png';
|
||||||
|
case JustMusicIcon.history:
|
||||||
|
return 'assets/images/history_icon.png';
|
||||||
|
case JustMusicIcon.theme:
|
||||||
|
return 'assets/images/theme_icon.png';
|
||||||
|
case JustMusicIcon.notification:
|
||||||
|
return 'assets/images/notification_icon.png';
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw 'assets/images/unknown.png';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|