mirror of
https://github.com/ErfanRht/MovieLab.git
synced 2025-05-17 05:55:54 +08:00
Add profile section
This commit is contained in:
BIN
assets/images/no_picture.png
Normal file
BIN
assets/images/no_picture.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
@ -20,3 +20,5 @@ enum ListName {
|
||||
FAVORITE_TRAILERS,
|
||||
PERSONAL_LIST
|
||||
}
|
||||
|
||||
enum ItemType { MOVIE, TV, ARTIST, OTHER, UNKNOWN }
|
||||
|
@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:hive_flutter/adapters.dart';
|
||||
import 'package:movielab/pages/main/profile/profile_controller.dart';
|
||||
import 'constants/colors.dart';
|
||||
import 'constants/routes.dart';
|
||||
import 'models/hive/hive_helper/register_adapters.dart';
|
||||
@ -29,6 +30,7 @@ void main() async {
|
||||
Get.put(MainController());
|
||||
Get.put(HomeDataController());
|
||||
Get.put(SearchBarController());
|
||||
Get.put(ProfileController());
|
||||
Get.put(CacheData());
|
||||
|
||||
runApp(const ProviderScope(child: App()));
|
||||
@ -43,6 +45,7 @@ class App extends StatelessWidget {
|
||||
title: 'MovieLab',
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: ThemeData(
|
||||
backgroundColor: kBackgroundColor,
|
||||
primaryColor: kPrimaryColor,
|
||||
textTheme: GoogleFonts.ubuntuTextTheme(
|
||||
Theme.of(context).textTheme,
|
||||
|
@ -8,6 +8,7 @@ ShowPreview convertHiveToShowPreview(HiveShowPreview hive) {
|
||||
id: hive.id,
|
||||
rank: hive.rank,
|
||||
title: hive.title,
|
||||
type: hive.type,
|
||||
crew: hive.crew,
|
||||
image: hive.image,
|
||||
year: hive.year,
|
||||
@ -46,6 +47,7 @@ HiveShowPreview convertShowPreviewToHive(
|
||||
..id = showPreview.id
|
||||
..rank = showPreview.rank
|
||||
..title = showPreview.title
|
||||
..type = showPreview.type
|
||||
..crew = showPreview.crew
|
||||
..image = showPreview.image
|
||||
..year = showPreview.year
|
||||
@ -84,6 +86,7 @@ Future<HiveShowPreview> convertFullShowToHive(
|
||||
..id = fullShow.id
|
||||
..rank = rank
|
||||
..title = fullShow.title
|
||||
..type = fullShow.type
|
||||
..crew = crew
|
||||
..image = fullShow.image
|
||||
..year = fullShow.year
|
||||
@ -118,6 +121,7 @@ Future<ShowPreview> convertFullShowToShowPreview(
|
||||
return ShowPreview(
|
||||
id: fullShow.id,
|
||||
title: fullShow.title,
|
||||
type: fullShow.type,
|
||||
crew: crew,
|
||||
image: fullShow.image,
|
||||
year: fullShow.year,
|
||||
|
@ -2,16 +2,17 @@ class ShowPreviewFields {
|
||||
static const int id = 0;
|
||||
static const int rank = 1;
|
||||
static const int title = 2;
|
||||
static const int crew = 3;
|
||||
static const int image = 4;
|
||||
static const int year = 5;
|
||||
static const int imDbRating = 6;
|
||||
static const int genres = 7;
|
||||
static const int countries = 8;
|
||||
static const int languages = 9;
|
||||
static const int companies = 10;
|
||||
static const int contentRating = 11;
|
||||
static const int similars = 12;
|
||||
static const int watchDate = 13;
|
||||
static const int watchTime = 14;
|
||||
static const int type = 3;
|
||||
static const int crew = 4;
|
||||
static const int image = 5;
|
||||
static const int year = 6;
|
||||
static const int imDbRating = 7;
|
||||
static const int genres = 8;
|
||||
static const int countries = 9;
|
||||
static const int languages = 10;
|
||||
static const int companies = 11;
|
||||
static const int contentRating = 12;
|
||||
static const int similars = 13;
|
||||
static const int watchDate = 14;
|
||||
static const int watchTime = 15;
|
||||
}
|
||||
|
@ -14,6 +14,8 @@ class HiveShowPreview extends HiveObject {
|
||||
late String rank;
|
||||
@HiveField(ShowPreviewFields.title)
|
||||
late String title;
|
||||
@HiveField(ShowPreviewFields.type)
|
||||
late String type;
|
||||
@HiveField(ShowPreviewFields.crew)
|
||||
late String crew;
|
||||
@HiveField(ShowPreviewFields.image)
|
||||
|
@ -20,24 +20,25 @@ class HiveShowPreviewAdapter extends TypeAdapter<HiveShowPreview> {
|
||||
..id = fields[0] as String
|
||||
..rank = fields[1] as String
|
||||
..title = fields[2] as String
|
||||
..crew = fields[3] as String
|
||||
..image = fields[4] as String
|
||||
..year = fields[5] as String
|
||||
..imDbRating = fields[6] as String
|
||||
..genres = fields[7] as String
|
||||
..countries = fields[8] as String
|
||||
..languages = fields[9] as String
|
||||
..companies = fields[10] as String
|
||||
..contentRating = fields[11] as String
|
||||
..similars = (fields[12] as List).cast<HiveShowPreview>()
|
||||
..watchDate = fields[13] as DateTime?
|
||||
..watchTime = fields[14] as TimeOfDay?;
|
||||
..type = fields[3] as String
|
||||
..crew = fields[4] as String
|
||||
..image = fields[5] as String
|
||||
..year = fields[6] as String
|
||||
..imDbRating = fields[7] as String
|
||||
..genres = fields[8] as String
|
||||
..countries = fields[9] as String
|
||||
..languages = fields[10] as String
|
||||
..companies = fields[11] as String
|
||||
..contentRating = fields[12] as String
|
||||
..similars = (fields[13] as List).cast<HiveShowPreview>()
|
||||
..watchDate = fields[14] as DateTime?
|
||||
..watchTime = fields[15] as TimeOfDay?;
|
||||
}
|
||||
|
||||
@override
|
||||
void write(BinaryWriter writer, HiveShowPreview obj) {
|
||||
writer
|
||||
..writeByte(15)
|
||||
..writeByte(16)
|
||||
..writeByte(0)
|
||||
..write(obj.id)
|
||||
..writeByte(1)
|
||||
@ -45,28 +46,30 @@ class HiveShowPreviewAdapter extends TypeAdapter<HiveShowPreview> {
|
||||
..writeByte(2)
|
||||
..write(obj.title)
|
||||
..writeByte(3)
|
||||
..write(obj.crew)
|
||||
..write(obj.type)
|
||||
..writeByte(4)
|
||||
..write(obj.image)
|
||||
..write(obj.crew)
|
||||
..writeByte(5)
|
||||
..write(obj.year)
|
||||
..write(obj.image)
|
||||
..writeByte(6)
|
||||
..write(obj.imDbRating)
|
||||
..write(obj.year)
|
||||
..writeByte(7)
|
||||
..write(obj.genres)
|
||||
..write(obj.imDbRating)
|
||||
..writeByte(8)
|
||||
..write(obj.countries)
|
||||
..write(obj.genres)
|
||||
..writeByte(9)
|
||||
..write(obj.languages)
|
||||
..write(obj.countries)
|
||||
..writeByte(10)
|
||||
..write(obj.companies)
|
||||
..write(obj.languages)
|
||||
..writeByte(11)
|
||||
..write(obj.contentRating)
|
||||
..write(obj.companies)
|
||||
..writeByte(12)
|
||||
..write(obj.similars)
|
||||
..write(obj.contentRating)
|
||||
..writeByte(13)
|
||||
..write(obj.watchDate)
|
||||
..write(obj.similars)
|
||||
..writeByte(14)
|
||||
..write(obj.watchDate)
|
||||
..writeByte(15)
|
||||
..write(obj.watchTime);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import '../actor_models/actor_preview_model.dart';
|
||||
import 'package:movielab/models/actor_models/actor_preview_model.dart';
|
||||
import 'show_preview_model.dart';
|
||||
|
||||
// Movie or TV show all detail model class
|
||||
@ -91,7 +91,7 @@ class FullShow {
|
||||
return FullShow(
|
||||
id: json['id'],
|
||||
title: json['title'] ?? "",
|
||||
type: json['type'] ?? "",
|
||||
type: json['type'] ?? json['role'] ?? "",
|
||||
image: json['image'].toString().replaceAll(
|
||||
"._V1_UX128_CR0,3,128,176_AL_.jpg", "._V1_Ratio0.6716_AL_.jpg"),
|
||||
images: ImageData.getImages(json['images']) ?? [],
|
||||
|
@ -6,6 +6,7 @@ class ShowPreview {
|
||||
final String id;
|
||||
final String rank;
|
||||
final String title;
|
||||
final String type;
|
||||
final String crew;
|
||||
final String image;
|
||||
final String year;
|
||||
@ -31,6 +32,7 @@ class ShowPreview {
|
||||
required this.id,
|
||||
required this.rank,
|
||||
required this.title,
|
||||
required this.type,
|
||||
required this.crew,
|
||||
required this.image,
|
||||
required this.year,
|
||||
@ -58,6 +60,7 @@ class ShowPreview {
|
||||
id: json['id'],
|
||||
rank: json['rank'] ?? "",
|
||||
title: json['title'],
|
||||
type: json['type'] ?? json['role'] ?? "",
|
||||
crew: json['crew'] ?? json['stars'] ?? "",
|
||||
image: json['image'].toString().replaceAll(
|
||||
"._V1_UX128_CR0,3,128,176_AL_.jpg", "._V1_Ratio0.6716_AL_.jpg"),
|
||||
|
@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:hive_flutter/adapters.dart';
|
||||
import 'package:movielab/models/show_models/show_preview_model.dart';
|
||||
import 'package:movielab/modules/Recommender/Recommender.dart';
|
||||
import 'package:movielab/pages/splash/get_user_data.dart';
|
||||
import '../../models/hive/convertor.dart';
|
||||
import '../../models/hive/models/show_preview.dart';
|
||||
|
||||
@ -45,6 +46,7 @@ class PreferencesShareholder {
|
||||
print("The item added to $listName");
|
||||
}
|
||||
recommender();
|
||||
updateUserStats();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -62,6 +64,7 @@ class PreferencesShareholder {
|
||||
}
|
||||
}
|
||||
recommender();
|
||||
updateUserStats();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:movielab/constants/colors.dart';
|
||||
import 'package:movielab/pages/main/profile/sections/lists.dart';
|
||||
|
||||
import 'sections/lists.dart';
|
||||
import 'sections/settings.dart';
|
||||
import 'sections/socials.dart';
|
||||
import 'sections/user_profile/user_profile.dart';
|
||||
|
||||
class ProfilePage extends StatelessWidget {
|
||||
const ProfilePage({Key? key}) : super(key: key);
|
||||
@ -28,6 +29,8 @@ class ProfilePage extends StatelessWidget {
|
||||
child: ListView(
|
||||
physics: const BouncingScrollPhysics(),
|
||||
children: const [
|
||||
SizedBox(height: 40),
|
||||
ProfilePageUserProfile(),
|
||||
SizedBox(height: 40),
|
||||
ProfilePageLists(),
|
||||
SizedBox(height: 40),
|
||||
|
101
lib/pages/main/profile/profile_controller.dart
Normal file
101
lib/pages/main/profile/profile_controller.dart
Normal file
@ -0,0 +1,101 @@
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class ProfileController extends GetxController {
|
||||
int watchedMoviesCount = 0;
|
||||
int watchedSeriesCount = 0;
|
||||
updateWatchedMoviesCount(int count) {
|
||||
watchedMoviesCount = count;
|
||||
update();
|
||||
}
|
||||
|
||||
updateWatchedSeriesCount(int count) {
|
||||
watchedSeriesCount = count;
|
||||
update();
|
||||
}
|
||||
|
||||
double imdbRatingAverage = 0;
|
||||
updateImdbRatingAverage(double value) {
|
||||
imdbRatingAverage = value;
|
||||
update();
|
||||
}
|
||||
|
||||
Map<String, int> genres = {};
|
||||
List<String> sortedGenres = [];
|
||||
int genresLength = 0;
|
||||
int genresOthers = 0;
|
||||
updateGenres(
|
||||
{required Map<String, int> genres,
|
||||
required List<String> sortedGenres,
|
||||
required int genresLength,
|
||||
required int genresOthers}) {
|
||||
this.genres = genres;
|
||||
this.sortedGenres = sortedGenres;
|
||||
this.genresLength = genresLength;
|
||||
this.genresOthers = genresOthers;
|
||||
update();
|
||||
}
|
||||
|
||||
Map<String, int> countries = {};
|
||||
List<String> sortedCountries = [];
|
||||
int countriesLength = 0;
|
||||
int countriesOthers = 0;
|
||||
updateCountries(
|
||||
{required Map<String, int> countries,
|
||||
required List<String> sortedCountries,
|
||||
required int countriesLength,
|
||||
required int countriesOthers}) {
|
||||
this.countries = countries;
|
||||
this.sortedCountries = sortedCountries;
|
||||
this.countriesLength = countriesLength;
|
||||
this.countriesOthers = countriesOthers;
|
||||
update();
|
||||
}
|
||||
|
||||
Map<String, int> languages = {};
|
||||
List<String> sortedLanguages = [];
|
||||
int languagesLength = 0;
|
||||
int languagesOthers = 0;
|
||||
updateLanguages(
|
||||
{required Map<String, int> languages,
|
||||
required List<String> sortedLanguages,
|
||||
required int languagesLength,
|
||||
required int languagesOthers}) {
|
||||
this.languages = languages;
|
||||
this.sortedLanguages = sortedLanguages;
|
||||
this.languagesLength = languagesLength;
|
||||
this.languagesOthers = languagesOthers;
|
||||
update();
|
||||
}
|
||||
|
||||
Map<String, int> companies = {};
|
||||
List<String> sortedCompanies = [];
|
||||
int companiesLength = 0;
|
||||
int companiesOthers = 0;
|
||||
updateCompanies(
|
||||
{required Map<String, int> companies,
|
||||
required List<String> sortedCompanies,
|
||||
required int companiesLength,
|
||||
required int companiesOthers}) {
|
||||
this.companies = companies;
|
||||
this.sortedCompanies = sortedCompanies;
|
||||
this.companiesLength = companiesLength;
|
||||
this.companiesOthers = companiesOthers;
|
||||
update();
|
||||
}
|
||||
|
||||
Map<String, int> contentRatings = {};
|
||||
List<String> sortedContentRatings = [];
|
||||
int contentRatingsLength = 0;
|
||||
int contentRatingsOthers = 0;
|
||||
updateContentRatings(
|
||||
{required Map<String, int> contentRatings,
|
||||
required List<String> sortedContentRatings,
|
||||
required int contentRatingsLength,
|
||||
required int contentRatingsOthers}) {
|
||||
this.contentRatings = contentRatings;
|
||||
this.sortedContentRatings = sortedContentRatings;
|
||||
this.contentRatingsLength = contentRatingsLength;
|
||||
this.contentRatingsOthers = contentRatingsOthers;
|
||||
update();
|
||||
}
|
||||
}
|
@ -123,7 +123,7 @@ class _ListStatsPageState extends State<ListStatsPage> {
|
||||
const SizedBox(
|
||||
height: 7.5,
|
||||
),
|
||||
Text("Avarage IMDB rating",
|
||||
Text("Avarage IMDb rating",
|
||||
style: TextStyle(
|
||||
color: Colors.white.withOpacity(0.75),
|
||||
fontSize: 15,
|
||||
|
@ -0,0 +1,58 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:movielab/constants/colors.dart';
|
||||
import 'package:movielab/widgets/buttons/glassmorphism_button.dart';
|
||||
import 'package:movielab/widgets/textfield_widget.dart';
|
||||
|
||||
import 'user_profile.dart';
|
||||
|
||||
class ProfilePageEditUserProfile extends StatelessWidget {
|
||||
const ProfilePageEditUserProfile({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: kBackgroundColor,
|
||||
appBar: AppBar(
|
||||
leading: const BackButton(),
|
||||
backgroundColor: Colors.transparent,
|
||||
elevation: 0,
|
||||
),
|
||||
body: ListView(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 32),
|
||||
physics: const BouncingScrollPhysics(),
|
||||
children: [
|
||||
userProfileImage(context, icon: Icons.add_a_photo, onTap: () {}),
|
||||
const SizedBox(height: 24),
|
||||
TextFieldWidget(
|
||||
label: 'Full Name',
|
||||
text: "user.name",
|
||||
onChanged: (name) {},
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
TextFieldWidget(
|
||||
label: 'Email',
|
||||
text: "user.email",
|
||||
onChanged: (email) {},
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
TextFieldWidget(
|
||||
label: 'About',
|
||||
text: "user.about",
|
||||
maxLines: 5,
|
||||
onChanged: (about) {},
|
||||
),
|
||||
const SizedBox(height: 40),
|
||||
GmButton(
|
||||
text: "Save",
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: MediaQuery.of(context).size.width / 5),
|
||||
backgroundColor: Colors.blue,
|
||||
color: Colors.white)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
213
lib/pages/main/profile/sections/user_profile/user_profile.dart
Normal file
213
lib/pages/main/profile/sections/user_profile/user_profile.dart
Normal file
@ -0,0 +1,213 @@
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_rating_bar/flutter_rating_bar.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:movielab/constants/colors.dart';
|
||||
import 'package:movielab/modules/tools/navigate.dart';
|
||||
import 'package:movielab/pages/main/profile/profile_controller.dart';
|
||||
|
||||
import 'edit_user_profile.dart';
|
||||
|
||||
class ProfilePageUserProfile extends StatelessWidget {
|
||||
const ProfilePageUserProfile({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetBuilder<ProfileController>(builder: (_) {
|
||||
return Center(
|
||||
child: Stack(
|
||||
children: [
|
||||
AnimatedContainer(
|
||||
height: 350,
|
||||
margin: const EdgeInsets.only(top: 64),
|
||||
padding: const EdgeInsets.only(top: 70),
|
||||
width: MediaQuery.of(context).size.width,
|
||||
decoration: BoxDecoration(
|
||||
color: kSecondaryColor,
|
||||
borderRadius: BorderRadius.circular(15)),
|
||||
duration: const Duration(milliseconds: 150),
|
||||
child: Column(
|
||||
children: [
|
||||
const Text(
|
||||
"Erfan Rahmati",
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 24),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
"@ErfanRht",
|
||||
style: TextStyle(
|
||||
color: Colors.white.withOpacity(0.5),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
Stack(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 25, vertical: 5),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
buildButton(
|
||||
context,
|
||||
_.watchedMoviesCount.toString(),
|
||||
"Watched\nMovies",
|
||||
),
|
||||
buildButton(
|
||||
context,
|
||||
_.watchedSeriesCount.toString(),
|
||||
"Watched\nSeries",
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
RatingBarIndicator(
|
||||
rating: (_.imdbRatingAverage / 10) - 0.15,
|
||||
itemBuilder: (context, index) => const Icon(
|
||||
Icons.star,
|
||||
color: kImdbColor,
|
||||
),
|
||||
unratedColor: kGreyColor,
|
||||
itemCount: 1,
|
||||
itemSize: 50,
|
||||
),
|
||||
Text(_.imdbRatingAverage.toString(),
|
||||
style: const TextStyle(
|
||||
color: kImdbColor,
|
||||
fontSize: 25,
|
||||
fontWeight: FontWeight.w700,
|
||||
)),
|
||||
const SizedBox(height: 3),
|
||||
Text(
|
||||
"Avarage IMDb rating",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Colors.white.withOpacity(0.75),
|
||||
fontSize: 12.5,
|
||||
fontWeight: FontWeight.w600),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 40, vertical: 7.5),
|
||||
child: Divider(
|
||||
color: Colors.white.withOpacity(0.75),
|
||||
thickness: 2.5,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: const [
|
||||
//buildButton(context, "Drama", "Favorite Genre"),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
userProfileImage(context, icon: Icons.edit, onTap: () {
|
||||
Navigate.pushHeroicTo(
|
||||
context, const ProfilePageEditUserProfile());
|
||||
}),
|
||||
],
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Widget buildButton(BuildContext context, String value, String text) =>
|
||||
MaterialButton(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||
onPressed: () {},
|
||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
value,
|
||||
style: const TextStyle(
|
||||
color: Colors.white, fontWeight: FontWeight.bold, fontSize: 24),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
text,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Colors.white.withOpacity(0.75),
|
||||
fontWeight: FontWeight.w600),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
Widget userProfileImage(BuildContext context,
|
||||
{required IconData icon, void Function()? onTap}) =>
|
||||
Center(
|
||||
child: Stack(
|
||||
children: [
|
||||
ClipOval(
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: Ink.image(
|
||||
image: const AssetImage("assets/images/no_picture.png"),
|
||||
fit: BoxFit.cover,
|
||||
width: 128,
|
||||
height: 128,
|
||||
child: InkWell(onTap: () {}),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
right: 4,
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
child: buildCircle(
|
||||
color: kSecondaryColor,
|
||||
all: 3,
|
||||
child: buildCircle(
|
||||
color: Colors.blue,
|
||||
all: 8,
|
||||
child: Icon(
|
||||
icon,
|
||||
color: Colors.white,
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
Widget buildCircle({
|
||||
required Widget child,
|
||||
required double all,
|
||||
required Color color,
|
||||
}) =>
|
||||
ClipOval(
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(all),
|
||||
color: color,
|
||||
child: child,
|
||||
),
|
||||
);
|
@ -1,7 +1,7 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:movielab/constants/types.dart';
|
||||
import 'package:movielab/modules/api/api_requester.dart';
|
||||
import 'package:movielab/pages/main/home/home_data_controller.dart';
|
||||
import '../../modules/api/api_requester.dart';
|
||||
|
||||
Future<RequestResult> getInitialData() async {
|
||||
final apiRequester = APIRequester();
|
||||
@ -13,7 +13,6 @@ Future<RequestResult> getInitialData() async {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
return RequestResult.FAILURE_USER_PROBLEM;
|
||||
}
|
||||
|
||||
if (Get.find<HomeDataController>().trendingMovies.isNotEmpty ||
|
||||
Get.find<HomeDataController>().trendingShows.isNotEmpty ||
|
||||
Get.find<HomeDataController>().inTheaters.isNotEmpty) {
|
||||
|
203
lib/pages/splash/get_user_data.dart
Normal file
203
lib/pages/splash/get_user_data.dart
Normal file
@ -0,0 +1,203 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:movielab/models/show_models/show_preview_model.dart';
|
||||
import 'package:movielab/modules/preferences/preferences_shareholder.dart';
|
||||
import 'package:movielab/pages/main/profile/profile_controller.dart';
|
||||
|
||||
Future getUserData() async {
|
||||
await updateUserStats();
|
||||
}
|
||||
|
||||
Future<bool> updateUserStats() async {
|
||||
PreferencesShareholder preferencesShareholder = PreferencesShareholder();
|
||||
List<List<ShowPreview>> allLists = await preferencesShareholder.getAllLists();
|
||||
List<ShowPreview> items = await getAllItems(allLists: allLists);
|
||||
|
||||
ProfileController controller = Get.find<ProfileController>();
|
||||
|
||||
if (allLists[0].isNotEmpty ||
|
||||
allLists[1].isNotEmpty ||
|
||||
allLists[2].isNotEmpty) {
|
||||
int watchedMovieCount = 0;
|
||||
int watchedShowCount = 0;
|
||||
for (ShowPreview item in allLists[2]) {
|
||||
if (item.type == "Movie") {
|
||||
watchedMovieCount++;
|
||||
} else if (item.type == "TVSeries") {
|
||||
watchedShowCount++;
|
||||
}
|
||||
}
|
||||
controller.updateWatchedMoviesCount(watchedMovieCount);
|
||||
controller.updateWatchedSeriesCount(watchedShowCount);
|
||||
|
||||
List<double> itemsImdbRatings = [];
|
||||
for (ShowPreview item in items) {
|
||||
try {
|
||||
itemsImdbRatings.add(double.parse(item.imDbRating));
|
||||
// ignore: empty_catches
|
||||
} catch (e) {}
|
||||
}
|
||||
final double itemsImdbRatingAverage = double.parse(
|
||||
((itemsImdbRatings.reduce((a, b) => a + b) / itemsImdbRatings.length))
|
||||
.toStringAsFixed(2));
|
||||
controller.updateImdbRatingAverage(itemsImdbRatingAverage);
|
||||
|
||||
Map<String, int> itemsGenres = {};
|
||||
int genresLength = 0;
|
||||
int genresOthers = 0;
|
||||
int i = 0;
|
||||
for (ShowPreview item in items) {
|
||||
for (String genre in item.genres!.split(", ")) {
|
||||
genresLength++;
|
||||
if (i > 6) {
|
||||
genresOthers++;
|
||||
}
|
||||
i++;
|
||||
if (itemsGenres.containsKey(genre)) {
|
||||
itemsGenres[genre] = itemsGenres[genre]! + 1;
|
||||
} else {
|
||||
itemsGenres[genre] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
final List<String> sortedGenres = itemsGenres.keys.toList();
|
||||
sortedGenres.sort((a, b) => itemsGenres[b]!.compareTo(itemsGenres[a]!));
|
||||
if (sortedGenres.length > 7) {
|
||||
for (int i = 0; i < sortedGenres.length; i++) {}
|
||||
}
|
||||
controller.updateGenres(
|
||||
genres: itemsGenres,
|
||||
sortedGenres: sortedGenres,
|
||||
genresLength: genresLength,
|
||||
genresOthers: genresOthers);
|
||||
|
||||
Map<String, int> itemCountries = {};
|
||||
int countriesLength = 0;
|
||||
int countriesOthers = 0;
|
||||
i = 0;
|
||||
for (ShowPreview item in items) {
|
||||
for (String country in item.countries!.split(", ")) {
|
||||
countriesLength++;
|
||||
if (i > 6) {
|
||||
countriesOthers++;
|
||||
}
|
||||
i++;
|
||||
if (itemCountries.containsKey(country)) {
|
||||
itemCountries[country] = itemCountries[country]! + 1;
|
||||
} else {
|
||||
itemCountries[country] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
final List<String> sortedCountries = itemCountries.keys.toList();
|
||||
sortedCountries
|
||||
.sort((a, b) => itemCountries[b]!.compareTo(itemCountries[a]!));
|
||||
if (sortedCountries.length > 7) {
|
||||
for (int i = 0; i < sortedCountries.length; i++) {}
|
||||
}
|
||||
controller.updateCountries(
|
||||
countries: itemCountries,
|
||||
sortedCountries: sortedCountries,
|
||||
countriesLength: countriesLength,
|
||||
countriesOthers: countriesOthers);
|
||||
|
||||
Map<String, int> languages = {};
|
||||
int languagesLength = 0;
|
||||
int languagesOthers = 0;
|
||||
i = 0;
|
||||
for (ShowPreview item in items) {
|
||||
for (String language in item.languages!.split(", ")) {
|
||||
languagesLength++;
|
||||
if (i > 6) {
|
||||
languagesOthers++;
|
||||
}
|
||||
i++;
|
||||
if (languages.containsKey(language)) {
|
||||
languages[language] = languages[language]! + 1;
|
||||
} else {
|
||||
languages[language] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
final List<String> sortedLanguages = languages.keys.toList();
|
||||
sortedLanguages.sort((a, b) => languages[b]!.compareTo(languages[a]!));
|
||||
if (sortedLanguages.length > 7) {
|
||||
for (int i = 0; i < sortedLanguages.length; i++) {}
|
||||
}
|
||||
controller.updateLanguages(
|
||||
languages: languages,
|
||||
sortedLanguages: sortedLanguages,
|
||||
languagesLength: languagesLength,
|
||||
languagesOthers: languagesOthers);
|
||||
|
||||
Map<String, int> companies = {};
|
||||
int companiesLength = 0;
|
||||
int companiesOthers = 0;
|
||||
i = 0;
|
||||
for (ShowPreview item in items) {
|
||||
for (String company in item.companies!.split(", ")) {
|
||||
companiesLength++;
|
||||
if (i > 6) {
|
||||
companiesOthers++;
|
||||
}
|
||||
i++;
|
||||
if (companies.containsKey(company)) {
|
||||
companies[company] = companies[company]! + 1;
|
||||
} else {
|
||||
companies[company] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
final List<String> sortedCompanies = companies.keys.toList();
|
||||
sortedCompanies.sort((a, b) => companies[b]!.compareTo(companies[a]!));
|
||||
if (sortedCompanies.length > 7) {
|
||||
for (int i = 0; i < sortedCompanies.length; i++) {}
|
||||
}
|
||||
controller.updateCompanies(
|
||||
companies: companies,
|
||||
sortedCompanies: sortedCompanies,
|
||||
companiesLength: companiesLength,
|
||||
companiesOthers: companiesOthers);
|
||||
|
||||
Map<String, int> contentRatings = {};
|
||||
int contentRatingsLength = 0;
|
||||
int contentRatingsOthers = 0;
|
||||
i = 0;
|
||||
for (ShowPreview item in items) {
|
||||
for (String contentRating in item.contentRating!.split(", ")) {
|
||||
contentRatingsLength++;
|
||||
if (i > 6) {
|
||||
contentRatingsOthers++;
|
||||
}
|
||||
i++;
|
||||
if (contentRatings.containsKey(contentRating)) {
|
||||
contentRatings[contentRating] = contentRatings[contentRating]! + 1;
|
||||
} else {
|
||||
contentRatings[contentRating] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
final List<String> sortedContentRatings = contentRatings.keys.toList();
|
||||
sortedContentRatings
|
||||
.sort((a, b) => contentRatings[b]!.compareTo(contentRatings[a]!));
|
||||
if (sortedContentRatings.length > 7) {
|
||||
for (int i = 0; i < sortedContentRatings.length; i++) {}
|
||||
}
|
||||
controller.updateContentRatings(
|
||||
contentRatings: contentRatings,
|
||||
sortedContentRatings: sortedContentRatings,
|
||||
contentRatingsLength: contentRatingsLength,
|
||||
contentRatingsOthers: contentRatingsOthers);
|
||||
print("User stats updated");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Future<List<ShowPreview>> getAllItems(
|
||||
{required List<List<ShowPreview>> allLists}) async {
|
||||
List<ShowPreview> items = [];
|
||||
for (List<ShowPreview> list in allLists) {
|
||||
items.addAll(list);
|
||||
}
|
||||
return items;
|
||||
}
|
@ -8,6 +8,7 @@ import '../../constants/colors.dart';
|
||||
import '../../constants/types.dart';
|
||||
import '../../modules/tools/system_ui_overlay_style.dart';
|
||||
import 'get_initial_data.dart';
|
||||
import 'get_user_data.dart';
|
||||
|
||||
class SplashScreen extends StatefulWidget {
|
||||
const SplashScreen({Key? key}) : super(key: key);
|
||||
@ -85,6 +86,7 @@ class _SplashScreenState extends State<SplashScreen> {
|
||||
getInitialData().then((result) {
|
||||
if (result == RequestResult.SUCCESS) {
|
||||
recommender();
|
||||
getUserData();
|
||||
Navigate.replaceTo(context, const MainPage());
|
||||
} else {
|
||||
setState(() {
|
||||
|
@ -11,7 +11,8 @@ class GmButton extends StatelessWidget {
|
||||
required this.color,
|
||||
this.backgroundColor,
|
||||
this.height = 35,
|
||||
this.width = 100})
|
||||
this.width = 100,
|
||||
this.padding = EdgeInsets.zero})
|
||||
: super(key: key);
|
||||
|
||||
final String text;
|
||||
@ -22,34 +23,38 @@ class GmButton extends StatelessWidget {
|
||||
final Color? backgroundColor;
|
||||
final double height;
|
||||
final double width;
|
||||
final EdgeInsets padding;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
borderRadius: BorderRadius.circular(radius),
|
||||
child: Container(
|
||||
width: width,
|
||||
height: height,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(radius),
|
||||
color: backgroundColor ?? color.withOpacity(0.25),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
icon != null
|
||||
? Icon(icon, color: color, size: 15)
|
||||
: const SizedBox.shrink(),
|
||||
icon != null
|
||||
? const SizedBox(
|
||||
width: 7.5,
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
Text(text,
|
||||
style: GoogleFonts.ubuntu(
|
||||
color: color, fontSize: 15, fontWeight: FontWeight.w500)),
|
||||
],
|
||||
return Padding(
|
||||
padding: padding,
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
borderRadius: BorderRadius.circular(radius),
|
||||
child: Container(
|
||||
width: width,
|
||||
height: height,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(radius),
|
||||
color: backgroundColor ?? color.withOpacity(0.25),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
icon != null
|
||||
? Icon(icon, color: color, size: 15)
|
||||
: const SizedBox.shrink(),
|
||||
icon != null
|
||||
? const SizedBox(
|
||||
width: 7.5,
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
Text(text,
|
||||
style: GoogleFonts.ubuntu(
|
||||
color: color, fontSize: 15, fontWeight: FontWeight.w500)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
68
lib/widgets/textfield_widget.dart
Normal file
68
lib/widgets/textfield_widget.dart
Normal file
@ -0,0 +1,68 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class TextFieldWidget extends StatefulWidget {
|
||||
final int maxLines;
|
||||
final String label;
|
||||
final String text;
|
||||
final ValueChanged<String> onChanged;
|
||||
|
||||
const TextFieldWidget({
|
||||
Key? key,
|
||||
this.maxLines = 1,
|
||||
required this.label,
|
||||
required this.text,
|
||||
required this.onChanged,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
TextFieldWidgetState createState() => TextFieldWidgetState();
|
||||
}
|
||||
|
||||
class TextFieldWidgetState extends State<TextFieldWidget> {
|
||||
late final TextEditingController controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
controller = TextEditingController(text: widget.text);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
widget.label,
|
||||
style: const TextStyle(
|
||||
color: Colors.white, fontWeight: FontWeight.bold, fontSize: 16),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
TextField(
|
||||
controller: controller,
|
||||
style: TextStyle(color: Colors.white.withOpacity(0.8)),
|
||||
decoration: InputDecoration(
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Colors.white.withOpacity(0.25), width: 2.0),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide:
|
||||
const BorderSide(color: Colors.blue, width: 2.5),
|
||||
borderRadius: BorderRadius.circular(12))),
|
||||
maxLines: widget.maxLines,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
@ -57,4 +57,4 @@ flutter:
|
||||
|
||||
assets:
|
||||
- assets/images/logos/
|
||||
- assets/images/erfan_rahmati_profile.jpg
|
||||
- assets/images/
|
Reference in New Issue
Block a user