improve: user profile boxn

This commit is contained in:
Erfan Rahmati
2022-08-13 17:18:00 +04:30
parent 0ac8e111e5
commit 02542c10b0
27 changed files with 387 additions and 91 deletions

View File

@ -14,6 +14,7 @@
<queries>
</queries>
<application
android:requestLegacyExternalStorage="true"
android:label="MovieLab"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">

View File

@ -8,6 +8,7 @@ import 'constants/colors.dart';
import 'constants/routes.dart';
import 'models/hive/hive_helper/register_adapters.dart';
import 'models/hive/models/show_preview.dart';
import 'models/hive/models/user.dart';
import 'modules/cache/cache_data.dart';
import 'pages/main/home/home_data_controller.dart';
import 'pages/main/main_controller.dart';
@ -21,6 +22,7 @@ void main() async {
// Initialize Hive and Hive Flutter
await Hive.initFlutter();
registerAdapters();
Hive.openBox<HiveUser>('user');
Hive.openBox<HiveShowPreview>('collection');
Hive.openBox<HiveShowPreview>('watchlist');
Hive.openBox<HiveShowPreview>('history');

View File

@ -1,7 +1,9 @@
import 'package:flutter/material.dart';
import 'package:movielab/models/hive/models/show_preview.dart';
import 'package:movielab/models/show_models/show_preview_model.dart';
import 'package:movielab/models/user_model/user_model.dart';
import '../show_models/full_show_model.dart';
import 'models/user.dart';
ShowPreview convertHiveToShowPreview(HiveShowPreview hive) {
return ShowPreview(
@ -153,3 +155,22 @@ Future<String> getShowCrew({required FullShow fullShow}) async {
crew = crewList.join(", ");
return crew;
}
User convertHiveToUser(HiveUser hive) {
return User(
name: hive.name,
username: hive.username,
email: hive.email,
imageUrl: hive.imageUrl,
phone: hive.phone,
);
}
HiveUser convertUserToHive(User user) {
return HiveUser()
..name = user.name
..username = user.username
..email = user.email
..imageUrl = user.imageUrl
..phone = user.phone;
}

View File

@ -0,0 +1,7 @@
class UserFields {
static const int name = 0;
static const int username = 1;
static const int email = 2;
static const int phone = 3;
static const int imageUrl = 4;
}

View File

@ -1,4 +1,5 @@
class HiveAdapters {
static const String showPreview = 'ShowPreviewAdapter';
static const String timeOfDay = 'TimeOfDayAdapter';
static const String user = 'UserAdapter';
}

View File

@ -1,4 +1,5 @@
class HiveTypes {
static const int showPreview = 0;
static const int timeOfDay = 1;
static const int user = 2;
}

View File

@ -1,8 +1,10 @@
import 'package:hive/hive.dart';
import 'package:movielab/models/hive/models/show_preview.dart';
import 'package:movielab/models/hive/models/time_of_day.g.dart';
import 'package:movielab/models/hive/models/user.dart';
void registerAdapters() {
Hive.registerAdapter(HiveShowPreviewAdapter());
Hive.registerAdapter(ShowPreviewAdapter());
Hive.registerAdapter(UserAdapter());
Hive.registerAdapter(TimeOfDayAdapter());
}

View File

@ -6,7 +6,7 @@ part of 'show_preview.dart';
// TypeAdapterGenerator
// **************************************************************************
class HiveShowPreviewAdapter extends TypeAdapter<HiveShowPreview> {
class ShowPreviewAdapter extends TypeAdapter<HiveShowPreview> {
@override
final int typeId = 0;
@ -79,7 +79,7 @@ class HiveShowPreviewAdapter extends TypeAdapter<HiveShowPreview> {
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is HiveShowPreviewAdapter &&
other is ShowPreviewAdapter &&
runtimeType == other.runtimeType &&
typeId == other.typeId;
}

View File

@ -0,0 +1,20 @@
import 'package:hive/hive.dart';
import 'package:movielab/models/hive/hive_helper/fields/user_fields.dart';
import 'package:movielab/models/hive/hive_helper/hive_adapters.dart';
import 'package:movielab/models/hive/hive_helper/hive_types.dart';
part 'user.g.dart';
@HiveType(typeId: HiveTypes.user, adapterName: HiveAdapters.user)
class HiveUser extends HiveObject {
@HiveField(UserFields.name)
late String name;
@HiveField(UserFields.username)
late String username;
@HiveField(UserFields.email)
late String email;
@HiveField(UserFields.phone)
late String phone;
@HiveField(UserFields.imageUrl)
late String imageUrl;
}

View File

@ -0,0 +1,52 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'user.dart';
// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************
class UserAdapter extends TypeAdapter<HiveUser> {
@override
final int typeId = 2;
@override
HiveUser read(BinaryReader reader) {
final numOfFields = reader.readByte();
final fields = <int, dynamic>{
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
};
return HiveUser()
..name = fields[0] as String
..username = fields[1] as String
..email = fields[2] as String
..phone = fields[3] as String
..imageUrl = fields[4] as String;
}
@override
void write(BinaryWriter writer, HiveUser obj) {
writer
..writeByte(5)
..writeByte(0)
..write(obj.name)
..writeByte(1)
..write(obj.username)
..writeByte(2)
..write(obj.email)
..writeByte(3)
..write(obj.phone)
..writeByte(4)
..write(obj.imageUrl);
}
@override
int get hashCode => typeId.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is UserAdapter &&
runtimeType == other.runtimeType &&
typeId == other.typeId;
}

View File

@ -0,0 +1,16 @@
// Movie or TV show preview model class
class User {
final String name;
final String username;
final String email;
final String phone;
final String imageUrl;
const User({
required this.name,
required this.username,
required this.email,
required this.phone,
required this.imageUrl,
});
}

View File

@ -5,9 +5,9 @@ import 'package:get/get.dart';
import 'package:http/http.dart' as http;
import 'package:movielab/constants/types.dart';
import 'package:movielab/models/actor_models/full_actor_model.dart';
import 'package:movielab/models/episode_model.dart';
import 'package:movielab/models/external_sites_model.dart';
import 'package:movielab/models/search_result_model.dart';
import 'package:movielab/models/show_models/episode_model.dart';
import 'package:movielab/models/show_models/external_sites_model.dart';
import 'package:movielab/models/show_models/search_result_model.dart';
import 'package:movielab/models/show_models/full_show_model.dart';
import 'package:movielab/models/show_models/show_preview_model.dart';
import 'package:movielab/modules/api/api_keys.dart';

View File

@ -1,7 +1,9 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:hive_flutter/adapters.dart';
import 'package:movielab/models/hive/models/user.dart';
import 'package:movielab/models/show_models/show_preview_model.dart';
import 'package:movielab/models/user_model/user_model.dart';
import 'package:movielab/modules/Recommender/Recommender.dart';
import 'package:movielab/pages/splash/get_user_data.dart';
import '../../models/hive/convertor.dart';
@ -110,4 +112,29 @@ class PreferencesShareholder {
}
return result;
}
Future<User> getUser() async {
Box<HiveUser> userBox = Hive.box<HiveUser>("user");
late HiveUser user;
if (userBox.isNotEmpty) {
user = userBox.getAt(0)!;
} else {
user = HiveUser()
..name = "Your name"
..username = "Your username"
..email = "Your email"
..phone = "Your phone"
..imageUrl = "Empty";
userBox.put(0, user);
}
return convertHiveToUser(user);
}
Future<bool> updateUser({required User user}) async {
Box<HiveUser> userBox = Hive.box<HiveUser>("user");
HiveUser hiveUser = convertUserToHive(user);
userBox.put(0, hiveUser);
return true;
}
}

View File

@ -1,6 +1,26 @@
import 'package:get/get.dart';
class ProfileController extends GetxController {
// User info
late String name;
late String username;
late String email;
late String phone;
late String imageUrl;
updateUserInfo(
{String? name,
String? username,
String? email,
String? phone,
String? imageUrl}) {
this.name = name ?? this.name;
this.username = username ?? this.username;
this.email = email ?? this.email;
this.phone = phone ?? this.phone;
this.imageUrl = imageUrl ?? this.imageUrl;
update();
}
int watchedMoviesCount = 0;
int watchedSeriesCount = 0;
updateWatchedMoviesCount(int count) {

View File

@ -1,5 +1,11 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:image_picker/image_picker.dart';
import 'package:movielab/constants/colors.dart';
import 'package:movielab/models/user_model/user_model.dart';
import 'package:movielab/modules/preferences/preferences_shareholder.dart';
import 'package:movielab/pages/main/profile/profile_controller.dart';
import 'package:movielab/pages/splash/get_user_data.dart';
import 'package:movielab/widgets/buttons/glassmorphism_button.dart';
import 'package:movielab/widgets/textfield_widget.dart';
@ -7,52 +13,97 @@ import 'user_profile_image.dart';
class ProfilePageEditUserProfile extends StatelessWidget {
const ProfilePageEditUserProfile({Key? key}) : super(key: key);
Future<bool> _onWillPop() async {
getUserInformation();
return true;
}
@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) {},
return GetBuilder<ProfileController>(builder: (_) {
return WillPopScope(
onWillPop: _onWillPop,
child: Scaffold(
backgroundColor: kBackgroundColor,
appBar: AppBar(
leading: const BackButton(),
backgroundColor: Colors.transparent,
elevation: 0,
),
const SizedBox(height: 24),
TextFieldWidget(
label: 'Email',
text: "user.email",
onChanged: (email) {},
body: ListView(
padding: const EdgeInsets.symmetric(horizontal: 32),
physics: const BouncingScrollPhysics(),
children: [
userProfileImage(context, icon: Icons.add_a_photo,
onTap: () async {
final ImagePicker picker = ImagePicker();
final XFile? image =
await picker.pickImage(source: ImageSource.gallery);
if (image != null) {
_.updateUserInfo(imageUrl: image.path);
}
}),
const SizedBox(height: 24),
TextFieldWidget(
label: 'Full Name',
text: _.name,
onChanged: (name) {
_.name = name;
},
),
const SizedBox(height: 24),
TextFieldWidget(
label: 'Username',
text: _.username,
onChanged: (username) {
_.username = username;
},
),
const SizedBox(height: 24),
TextFieldWidget(
label: 'Email',
text: _.email,
onChanged: (email) {
_.email = email;
},
),
const SizedBox(height: 24),
TextFieldWidget(
label: 'Phone number',
text: _.phone,
onChanged: (email) {
_.phone = email;
},
),
const SizedBox(height: 40),
GmButton(
text: "Save",
onTap: () {
PreferencesShareholder preferencesShareholder =
PreferencesShareholder();
preferencesShareholder.updateUser(
user: User(
name: _.name,
username: _.username,
email: _.email,
phone: _.phone,
imageUrl: _.imageUrl));
_.updateUserInfo(
name: _.name,
username: _.username,
email: _.email,
phone: _.phone,
imageUrl: _.imageUrl);
Navigator.pop(context);
},
padding: EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width / 5),
backgroundColor: Colors.blue,
color: Colors.white)
],
),
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)
],
),
);
),
);
});
}
}

View File

@ -29,16 +29,16 @@ class ProfilePageUserProfile extends StatelessWidget {
duration: const Duration(milliseconds: 150),
child: Column(
children: [
const Text(
"Erfan Rahmati",
style: TextStyle(
Text(
_.name,
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 24),
),
const SizedBox(height: 4),
Text(
"@ErfanRht",
_.username,
style: TextStyle(
color: Colors.white.withOpacity(0.5),
fontWeight: FontWeight.w600,

View File

@ -1,46 +1,53 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:movielab/constants/colors.dart';
import 'package:movielab/pages/main/profile/profile_controller.dart';
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,
GetBuilder<ProfileController>(
builder: (_) => Center(
child: Stack(
children: [
ClipOval(
child: Material(
color: Colors.transparent,
child: Ink.image(
image: _.imageUrl != "Empty"
? FileImage(File(_.imageUrl)) as ImageProvider
: 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,

View File

@ -3,7 +3,7 @@ import 'package:flutter_rating_bar/flutter_rating_bar.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:movielab/constants/colors.dart';
import 'package:movielab/models/episode_model.dart';
import 'package:movielab/models/show_models/episode_model.dart';
import 'package:movielab/pages/show/show_box/show_box_common.dart';
class EpisodeShowBox extends StatelessWidget {

View File

@ -4,7 +4,7 @@ import 'package:google_fonts/google_fonts.dart';
import 'package:movielab/pages/actor/actor_page/actor_page.dart';
import 'package:movielab/pages/show/show_box/show_box_common.dart';
import 'package:movielab/pages/show/show_page/show_page.dart';
import '../../../models/search_result_model.dart';
import '../../../models/show_models/search_result_model.dart';
import '../../../modules/tools/navigate.dart';
class SearchShowBox extends StatelessWidget {

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:movielab/constants/colors.dart';
import 'package:movielab/models/external_sites_model.dart';
import 'package:movielab/models/show_models/external_sites_model.dart';
import 'package:movielab/models/show_models/full_show_model.dart';
import 'package:movielab/modules/api/api_requester.dart';
import 'package:movielab/widgets/section_title.dart';

View File

@ -1,12 +1,29 @@
import 'package:get/get.dart';
import 'package:movielab/models/show_models/show_preview_model.dart';
import 'package:movielab/models/user_model/user_model.dart';
import 'package:movielab/modules/preferences/preferences_shareholder.dart';
import 'package:movielab/pages/main/profile/profile_controller.dart';
Future getUserData() async {
await getUserInformation();
await updateUserStats();
}
Future<bool> getUserInformation() async {
PreferencesShareholder preferencesShareholder = PreferencesShareholder();
ProfileController controller = Get.find<ProfileController>();
User user = await preferencesShareholder.getUser();
controller.updateUserInfo(
name: user.name,
username: user.username,
email: user.email,
phone: user.phone,
imageUrl: user.imageUrl,
);
return true;
}
Future<bool> updateUserStats() async {
PreferencesShareholder preferencesShareholder = PreferencesShareholder();
List<List<ShowPreview>> allLists = await preferencesShareholder.getAllLists();

View File

@ -62,6 +62,7 @@ class TextFieldWidgetState extends State<TextFieldWidget> {
const BorderSide(color: Colors.blue, width: 2.5),
borderRadius: BorderRadius.circular(12))),
maxLines: widget.maxLines,
onChanged: widget.onChanged,
),
],
);

View File

@ -183,6 +183,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
cross_file:
dependency: transitive
description:
name: cross_file
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.3+1"
crypto:
dependency: transitive
description:
@ -272,6 +279,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.7"
flutter_rating_bar:
dependency: "direct main"
description:
@ -415,6 +429,41 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "4.0.0"
image_picker:
dependency: "direct main"
description:
name: image_picker
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.5+3"
image_picker_android:
dependency: transitive
description:
name: image_picker_android
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.5+2"
image_picker_for_web:
dependency: transitive
description:
name: image_picker_for_web
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.8"
image_picker_ios:
dependency: transitive
description:
name: image_picker_ios
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.5+6"
image_picker_platform_interface:
dependency: transitive
description:
name: image_picker_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.6.1"
io:
dependency: transitive
description:

View File

@ -40,6 +40,7 @@ dependencies:
url_launcher: ^6.1.4
fl_chart: ^0.55.0
share_plus: ^4.0.10
image_picker: ^0.8.5+3