name27 / flutter

0 stars 0 forks source link

프로필 앱 #95

Open name27 opened 1 year ago

name27 commented 1 year ago

image image image image

main.dart

import 'package:flutter/material.dart';
import 'package:profile_app/page/main_page.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MainPage(),
    );
  }
}

main_page.dart

import 'package:animate_do/animate_do.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:profile_app/model/profile.dart';
import 'package:profile_app/widget/contactTile.dart';

class MainPage extends StatefulWidget {
  const MainPage({super.key});

  @override
  State<MainPage> createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  Future<List<Profile>> getData() async {
    Dio dio = Dio();
    var url = 'https://jsonplaceholder.typicode.com/users';
    var res = await dio.get(url);
    if (res.statusCode == 200) {
      var data = List<Map<String, dynamic>>.from(res.data);
      return data.map((e) => Profile.fromMap(e)).toList();
    }
    return [];
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('My Contacts'),
        centerTitle: true,
        foregroundColor: Colors.black,
        backgroundColor: Colors.transparent,
        elevation: 0,
      ),
      body: FutureBuilder(
        future: getData(),
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.done &&
              snapshot.data != null) {
            return ListView.builder(
                physics: BouncingScrollPhysics(),
                itemCount: snapshot.data?.length ?? 0,
                itemBuilder: (context, index) => FadeInRight(
                    delay: Duration(milliseconds: index * 100),
                    duration: Duration(milliseconds: 1200),
                    child: ContactTile(profile: snapshot.data![index])));
          }
          return Center(child: CircularProgressIndicator());
        },
      ),
    );
  }
}

contact_page.dart

import 'package:animate_do/animate_do.dart';
import 'package:flutter/material.dart';
import 'package:profile_app/model/profile.dart';

class ContactPage extends StatelessWidget {
  const ContactPage({super.key, required this.profile, required this.imgUrl});
  final Profile profile;
  final String imgUrl;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      extendBodyBehindAppBar: true,
      appBar: AppBar(
        title: Text(profile.name),
        centerTitle: true,
        backgroundColor: Colors.transparent,
        elevation: 0,
      ),
      body: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Stack(children: [
            Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Container(
                  height: 250,
                  decoration: BoxDecoration(
                      image: DecorationImage(
                          image: NetworkImage(imgUrl),
                          fit: BoxFit.cover,
                          colorFilter: ColorFilter.mode(
                              Colors.black45, BlendMode.darken))),
                ),
                SizedBox(
                  height: 50,
                ),
                FadeIn(
                  delay: Duration(milliseconds: 300),
                  duration: Duration(milliseconds: 2000),
                  child: Padding(
                    padding: const EdgeInsets.only(left: 12.0),
                    child: Text(
                      profile.name,
                      style: TextStyle(fontSize: 30),
                    ),
                  ),
                )
              ],
            ),
            Positioned(
              bottom: 45,
              child: Padding(
                padding: const EdgeInsets.only(left: 12.0),
                child: CircleAvatar(
                  backgroundImage: NetworkImage(imgUrl),
                  radius: 50,
                ),
              ),
            )
          ]),
          Divider(),
          FadeIn(
            delay: Duration(milliseconds: 1500),
            duration: Duration(milliseconds: 2000),
            child: Padding(
              padding: const EdgeInsets.only(top: 8, left: 12.0),
              child: Wrap(
                spacing: 300,
                runSpacing: 8,
                children: [
                  Text(
                    'Information',
                    style: TextStyle(fontSize: 22),
                  ),
                  Row(
                    children: [
                      Icon(Icons.mail),
                      SizedBox(
                        width: 5,
                      ),
                      Text(profile.email)
                    ],
                  ),
                  Row(
                    children: [
                      Icon(Icons.phone),
                      SizedBox(
                        width: 5,
                      ),
                      Text(profile.phone)
                    ],
                  ),
                  Row(
                    children: [
                      Icon(Icons.room),
                      SizedBox(
                        width: 5,
                      ),
                      Text(profile.address.city),
                      Text(', '),
                      Text(profile.address.street),
                      Text(', '),
                      Text(profile.address.suite)
                    ],
                  ),
                ],
              ),
            ),
          ),
          Divider(
            height: 30,
          ),
          FadeIn(
            delay: Duration(milliseconds: 2500),
            duration: Duration(milliseconds: 2000),
            child: Padding(
              padding: const EdgeInsets.only(left: 12.0),
              child: Wrap(
                spacing: 300,
                runSpacing: 8,
                children: [
                  Text(
                    'Company',
                    style: TextStyle(fontSize: 22),
                  ),
                  Text(profile.company.name),
                  Text(profile.company.catchPhrase),
                  Text(profile.company.bs)
                ],
              ),
            ),
          )
        ],
      ),
    );
  }
}

contactTile.dart

import 'package:flutter/material.dart';
import 'package:profile_app/model/profile.dart';
import 'package:profile_app/page/contact_page.dart';

class ContactTile extends StatelessWidget {
  const ContactTile({super.key, required this.profile});
  final Profile profile;

  @override
  Widget build(BuildContext context) {
    var imgUrl =
        'https://xsgames.co/randomusers/assets/avatars/male/${profile.id}.jpg';
    return GestureDetector(
      onTap: () {
        Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => ContactPage(
                profile: profile,
                imgUrl: imgUrl,
              ),
            ));
      },
      child: ListTile(
        leading: CircleAvatar(
          backgroundImage: NetworkImage(imgUrl),
        ),
        title: Text(profile.name),
        subtitle: Text(profile.email),
        trailing: Icon(Icons.navigate_next),
      ),
    );
  }
}

profile.dart

class Geo {
  String lat;
  String lng;

  Geo({required this.lat, required this.lng});

  factory Geo.fromMap(Map<String, dynamic> map) {
    return Geo(lat: map['lat'], lng: map['lng']);
  }
}

class Address {
  String street;
  String suite;
  String city;
  String zipcode;
  Geo geo;

  Address(
      {required this.street,
      required this.suite,
      required this.city,
      required this.zipcode,
      required this.geo});

  factory Address.fromMap(Map<String, dynamic> map) {
    return Address(
        street: map['street'],
        suite: map['suite'],
        city: map['city'],
        zipcode: map['zipcode'],
        geo: Geo.fromMap(map['geo']));
  }
}

class Company {
  String name;
  String catchPhrase;
  String bs;

  Company({required this.name, required this.catchPhrase, required this.bs});

  factory Company.fromMap(Map<String, dynamic> map) {
    return Company(
        name: map['name'], catchPhrase: map['catchPhrase'], bs: map['bs']);
  }
}

class Profile {
  int id;
  String name;
  String username;
  String email;
  Address address;
  String phone;
  String website;
  Company company;

  Profile(
      {required this.id,
      required this.name,
      required this.username,
      required this.email,
      required this.address,
      required this.phone,
      required this.website,
      required this.company});

  factory Profile.fromMap(Map<String, dynamic> map) {
    return Profile(
        id: map['id'],
        name: map['name'],
        username: map['username'],
        email: map['email'],
        address: Address.fromMap(map['address']),
        phone: map['phone'],
        website: map['website'],
        company: Company.fromMap(map['company']));
  }
}