Tutorial Flutter Membuat Halaman Profil

Artikel kali ini akan tentang Tutorial Flutter Membuat Halaman Profil. Kita akan membangun UI serta membuat proses untuk update ke table database melalui API. Artikel ini adalah lanjutan dari Tutorial Flutter Membuat Halaman Dashboard. Pada halaman profile nanti kita akan mampu untuk mengubah data, data yang dapat di ubah adalah gambar profil, nama dan no telpon.

Tutorial Flutter Membuat Halaman Profil

Kita akan menggunakan image_picker , link nya  https://pub.dev/packages/image_picker . Jadi ubah pubspec.yaml menjadi seperti ini

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^0.1.3
  flutter_bloc: ^4.0.0
  equatable: ^1.1.1
  rxdart: 0.24.0
  http: ^0.12.1
  shared_preferences: ^0.5.7+2
  google_fonts: ^1.1.0
  intl: ^0.16.1
  image_picker: ^0.6.6+1

Halaman Profil pada Flutter

Sekarang kita akan memulai dengan membangun form atau tampilannya. Seperti ini tampilan yang akan kita buat

gambar di atas adalah gambar ketika state halaman profile Profileinitial, dan jika kita menekan tombol biru state halaman profile akan merubah menjadi EditingProfile , tampilannya pun akan berubah menjadi seperti ini

Tutorial Flutter Membuat Halaman Profil

Untuk mengambil gambar dari galeri atau kamera, kita dapat menekan ikon pensil. Ketika kita menak ikon itu kita akan menjalankan fungsi

Future getImage() async {
  var image = await ImagePicker.pickImage(source: ImageSource.gallery);
   setState(() {
     _image = image;
   });
 }

Sebelumnya ada sedikit perubahan di file user_repository.dart tepat nya di fungsi  getUser() , berikut isi fungsi tersebut

Future<User> getUser() async {
   SharedPreferences prefs = await SharedPreferences.getInstance();
   var email =
       (prefs.getString("email") == null) ? "" : prefs.getString("email");
   User user;

   if (email != "") {
     var result = await http
         .post(Configuration.url + 'Api/getUser', body: {'email': email});
     var datauser = json.decode(result.body);

     user = new User(
       fullName: datauser["name"],
       phone: datauser["phone"],
       email: datauser["email"],
       active: prefs.getInt("active"),
       imageFileName: datauser["imageFileName"],
     );
   }
   return user;
 }

Jadi kita akan mengambil session email dari user yang sedang login lalu mengambil datanya kembali lewat API. Dari api tersebut kita akan mendapatkan hasil seperti ini

{
    "id": "17",
    "email": "boby12kurniawan@gmail.com",
    "password": "e10adc3949ba59abbe56e057f20f883e",
    "name": "Boby Kurniawan",
    "phone": "+6289688965164",
    "imageFileName": "image_picker_305102C6-4A15-4088-B596-316557B4390F-2351-00000614A3BFBE78.jpg",
    "active": "1"
}

Berikut file profile_dart

class Profile extends StatefulWidget {
  User user;

  Profile({@required this.user});

  @override
  _ProfileState createState() => _ProfileState();
}

class _ProfileState extends State<Profile> {
  File _image;
  final TextEditingController _emailController = TextEditingController();
  final TextEditingController _nameController = TextEditingController();
  final TextEditingController _phoneController = TextEditingController();
  bool editMode = false;
  final _formKey = GlobalKey<FormState>();

  @override
  void initState() {
    _emailController.text = widget.user.email;
    _nameController.text = widget.user.fullName;
    _phoneController.text = widget.user.phone;
    super.initState();
  }

  Future getImage() async {
    var image = await ImagePicker.pickImage(source: ImageSource.gallery);
    setState(() {
      _image = image;
    });
  }

  @override
  Widget build(BuildContext context) {
    final ProfileBloc profileBloc = BlocProvider.of<ProfileBloc>(context);
    return BlocListener<ProfileBloc, ProfileState>(
      listener: (context, state) async {
        if (state is EditingProfile) {
          editMode = true;
        } else if (state is Loading) {
          Scaffold.of(context)
            ..hideCurrentSnackBar()
            ..showSnackBar(
              SnackBar(
                content: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    Text("Processing"),
                    CircularProgressIndicator(),
                  ],
                ),
              ),
            );
        } else if (state is ProfileUpdated) {
          editMode = false;
          Scaffold.of(context)
            ..hideCurrentSnackBar()
            ..showSnackBar(
              SnackBar(
                content: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    Text(state.message),
                    Icon(
                      Icons.check,
                      color: Colors.greenAccent,
                    ),
                  ],
                ),
              ),
            );
          BlocProvider.of<AuthenticationBloc>(context).add(LoggedIn());

        } else if (state is ProfileError) {
          editMode = true;
          Scaffold.of(context)
            ..hideCurrentSnackBar()
            ..showSnackBar(
              SnackBar(
                content: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    Text(state.message),
                    Icon(
                      Icons.warning,
                      color: Colors.redAccent,
                    ),
                  ],
                ),
              ),
            );
        } else {
          editMode = false;
        }
      },
      child: Padding(
        padding: const EdgeInsets.only(top: 8.0, left: 18, right: 16),
        child: BlocBuilder<ProfileBloc, ProfileState>(
          builder: (context, state) {
            return ListView(
              children: <Widget>[
                Form(
                  key: _formKey,
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.start,
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: <Widget>[
                      Row(
                        children: <Widget>[
                          Flexible(
                            child: Container(
                              constraints: BoxConstraints.tight(
                                  Size(double.infinity, 170)),
                              child: Stack(
                                alignment: AlignmentDirectional.center,
                                children: <Widget>[
                                  Positioned(
                                    top: 0.0,
                                    child: CircleAvatar(
                                      radius: 70.0,
                                      backgroundImage: NetworkImage((widget
                                                  .user.imageFileName ==
                                              "")
                                          ? 'https://via.placeholder.com/150?text=' +
                                              widget.user.fullName[0]
                                          : Configuration.url +
                                              "assets/fileupload/" +
                                              widget.user.imageFileName),
                                      backgroundColor: Colors.transparent,
                                    ),
                                  ),
                                  (editMode)
                                      ? Positioned(
                                          top: 4,
                                          right: 110,
                                          child: CircleAvatar(
                                            backgroundColor:
                                                MyAppTheme.nearlyBlue,
                                            radius: 18,
                                            child: IconButton(
                                              padding: EdgeInsets.zero,
                                              icon: Icon(Icons.edit),
                                              color: Colors.white,
                                              onPressed: () {
                                                getImage();
                                              },
                                            ),
                                          ),
                                        )
                                      : Container(),
                                ],
                              ),
                            ),
                          ),
                        ],
                      ),
                      TextFormField(
                        readOnly: true,
                        controller: _emailController,
                        decoration: InputDecoration(
                          icon: Icon(
                            Icons.email,
                            color: Colors.lightBlueAccent,
                          ),
                          labelText: 'Email',
                        ),
                        keyboardType: TextInputType.emailAddress,
                        autocorrect: false,
                      ),
                      TextFormField(
                        readOnly: !editMode,
                        validator: validateName,
                        keyboardType: TextInputType.text,
                        controller: _nameController,
                        decoration: InputDecoration(
                          icon: Icon(
                            Icons.person,
                            color: Colors.lightBlueAccent,
                          ),
                          labelText: 'Fullname',
                        ),
                        autocorrect: false,
                      ),
                      TextFormField(
                        readOnly: !editMode,
                        keyboardType: TextInputType.phone,
                        controller: _phoneController,
                        decoration: InputDecoration(
                          icon: Icon(
                            Icons.phone_android,
                            color: Colors.lightBlueAccent,
                          ),
                          labelText: 'Phone',
                        ),
                        autocorrect: false,
                        validator: validatePhone,
                      ),
                      SizedBox(
                        height: 50,
                      ),
                      (!editMode)
                          ? Row(
                              mainAxisAlignment: MainAxisAlignment.center,
                              children: <Widget>[
                                FlatButton(
                                  color: Colors.lightBlueAccent,
                                  child: Text("Change Profile Information"),
                                  onPressed: () {
                                    profileBloc.add(ClickedEditButton());
                                  },
                                ),
                              ],
                            )
                          : Row(
                              mainAxisAlignment: MainAxisAlignment.center,
                              children: <Widget>[
                                FlatButton(
                                  color: Colors.redAccent,
                                  child: Text("Update"),
                                  onPressed: () async {
                                    if (_image == null &&
                                        widget.user.imageFileName == "") {
                                      Scaffold.of(context)
                                        ..hideCurrentSnackBar()
                                        ..showSnackBar(
                                          SnackBar(
                                            content: Row(
                                              mainAxisAlignment:
                                                  MainAxisAlignment
                                                      .spaceBetween,
                                              children: [
                                                Text(
                                                    'Please choose your image'),
                                                Icon(
                                                  Icons.warning,
                                                  color: Colors.redAccent,
                                                ),
                                              ],
                                            ),
                                          ),
                                        );
                                      return;
                                    }
                                    if (_formKey.currentState.validate()) {
                                      _formKey.currentState.save();
                                    profileBloc.add(Submitting(
                                          email: _emailController.text,
                                          name: _nameController.text,
                                          phone: _phoneController.text,
                                          image: _image));
                                    }


                                  },
                                ),
                              ],
                            )
                    ],
                  ),
                )
              ],
            );
          },
        ),
      ),
    );
  }

  String validatePhone(String value) {
    Pattern pattern =
        r'\+(9[976]\d|8[987530]\d|6[987]\d|5[90]\d|42\d|3[875]\d|2[98654321]\d|9[8543210]|8[6421]|6[6543210]|5[87654321]|4[987654310]|3[9643210]|2[70]|7|1)\d{1,14}$';
    RegExp regex = new RegExp(pattern);
    if (!regex.hasMatch(value))
      return 'Enter a valid Phone';
    else
      return null;
  }

  String validateName(String value) {
    if (value.length < 1)
      return 'This field is required';
    else
      return null;
  }
}

Pada form nanti, kita hanya bisa mengubah nama, no telp dan gambar. Secara default, field field itu belum bisa di edit. Ketika kita mengklik tombol Change Profile Information, kita akan menjalankan event ClickedEditButton lalu akan mengubah state menjadi EditingProfile. Kita juga ada pengecekan gambar, ketika user berlum pernah mengganti gambar atau mengupload gambar, user di wajibkan untuk mengupload gambar.



Sekarang kita akan membuat folder bloc didalam folder profile

profile_bloc.dart

class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
  final userRepository = UserRepository();

  @override
  ProfileState get initialState => Profileinitial();

  @override
  Stream<ProfileState> mapEventToState(ProfileEvent event) async* {
    yield Profileinitial();
    if (event is ClickedEditButton) {
      yield EditingProfile(isEditing: true);
    }
    if (event is Submitting) {
      yield Loading();
      try {
        await userRepository.updateUser(
            email: event.email,
            name: event.name,
            phone: event.phone,
            imageFile: event.image);
        yield ProfileUpdated(message: "Profile updated");
      } catch (e) {
        yield ProfileError(message: e);
      }
    }
  }
}

profile_event.dart

abstract class ProfileEvent extends Equatable {
  const ProfileEvent();

  @override
  List<Object> get props => [];
}

class ClickedEditButton extends ProfileEvent {}

class Submitting extends ProfileEvent {
  final String email;
  final String name;
  final String phone;
  final File image;

  const Submitting(
      {@required this.email,
        @required this.name,
        @required this.phone,
        @required this.image});

  @override
  List<Object> get props => [email, name, phone, image];
}

profile_state.dart

abstract class ProfileState extends Equatable {
  const ProfileState();

  @override
  List<Object> get props => [];
}

class Loading extends ProfileState {}

class ProfileUpdated extends ProfileState {
  final String message;

  ProfileUpdated({this.message});

  @override
  List<Object> get props => [message];
}

class ProfileError extends ProfileState {
  final String message;

  ProfileError({this.message});

  @override
  List<Object> get props => [message];
}

class Profileinitial extends ProfileState {}

class EditingProfile extends ProfileState {
  final bool isEditing;

  EditingProfile({this.isEditing});

  @override
  List<Object> get props => [isEditing];
}

Sekian untuk artikel yang berjudul Tutorial Flutter Membuat Halaman Profil, semoga bermanfaat

Tinggalkan Balasan

Subscribe To Our Newsletter

Subscribe To Our Newsletter

Kami memberikan tutorial baru tiap harinya !!!

You have Successfully Subscribed!

%d blogger menyukai ini: