<file_sep>import React from 'react';
import {
  Animated,
  Easing,
  Keyboard,
  Platform,
  StyleSheet,
  TouchableWithoutFeedback,
} from 'react-native';

export class AvoidKeyboard extends React.Component {
  static defaultProps = {
    offset: height => height,
    autoDismiss: true,
  };

  translateY = new Animated.Value(0);

  animationDuration = Platform.select({
    android: 160,
    default: 250,
  });

  // @ts-ignore
  showEvent = Platform.select({
    android: 'keyboardDidShow',
    default: 'keyboardWillShow',
  });

  // @ts-ignore
  hideEvent = Platform.select({
    android: 'keyboardDidHide',
    default: 'keyboardWillHide',
  });

  keyboardShowSubscription;
  keyboardHideSubscription;

  componentDidMount() {
    this.keyboardShowSubscription = Keyboard.addListener(
      this.showEvent,
      this.onKeyboardShow,
    );
    this.keyboardHideSubscription = Keyboard.addListener(
      this.hideEvent,
      this.onKeyboardHide,
    );
  }

  componentWillUnmount() {
    this.keyboardShowSubscription.remove();
    this.keyboardHideSubscription.remove();
  }

  onKeyboardShow = event => {
    const offset = -this.props.offset(event.endCoordinates.height);

    this.createTranslateAnimation({offset}).start();
  };

  onKeyboardHide = event => {
    const offset = 0;

    this.createTranslateAnimation({offset}).start();
  };

  onContainerPress = () => {
    Keyboard.dismiss();
  };

  getComponentStyle = source => {
    return {
      ...styles.container,
      ...styles.transform(this.translateY),
      ...StyleSheet.flatten(source),
    };
  };

  createTranslateAnimation = params => {
    const {offset} = params;

    return Animated.timing(this.translateY, {
      toValue: offset,
      duration: this.animationDuration,
      easing: Easing.linear,
    });
  };

  render() {
    const {style, autoDismiss, ...restProps} = this.props;
    const componentStyle = this.getComponentStyle(style);

    return (
      <TouchableWithoutFeedback
        onPress={this.onContainerPress}
        disabled={!autoDismiss}>
        <Animated.View style={componentStyle} {...restProps} />
      </TouchableWithoutFeedback>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  // @ts-ignore
  transform: y => ({
    transform: [{translateY: y}],
  }),
});
<file_sep>/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * Generated with the UI Kitten template
 * https://github.com/akveo/react-native-ui-kitten
 *
 * Documentation: https://akveo.github.io/react-native-ui-kitten/docs
 *
 * @format
 */

import React from 'react';
import {AsyncStorage} from 'react-native';
import {
  ApplicationProvider,
  Button,
  Icon,
  IconRegistry,
  Layout,
  Text,
} from 'react-native-ui-kitten';
// import {ApplicationLoader} from './src/core/appLoader/applicationLoader';
import {mapping, light as theme} from '@eva-design/eva';
import {EvaIconsPack} from '@ui-kitten/eva-icons';
import {AppNavigator} from './src/components/AppNavigator';
import FlashMessage, {showMessage} from 'react-native-flash-message';
import SplashScreen from 'react-native-splash-screen';
import axios from 'axios';
import _ from 'lodash';

/**
 * Use any valid `name` property from eva icons (e.g `github`, or `heart-outline`)
 * https://akveo.github.io/eva-icons
 */

function wait(timeout) {
  return new Promise(resolve => {
    setTimeout(resolve, timeout);
  });
}

class App extends React.Component {
  componentDidMount() {
    // this.messageChecker();
    AsyncStorage.setItem(
      'chatContext',
      JSON.stringify({
        chatMsno: 0,
        msno: 0,
        latestId: 0,
        messages: [],
      }),
    );
    this.listenChatMessage();
    SplashScreen.hide();
  }

  messageChecker = async () => {
    AsyncStorage.getItem('user')
      .then(userData => {
        // init local messages
        if (userData) {
          var user = JSON.parse(userData);
          axios({
            method: 'get',
            url: 'https://kkfriends.app/chat-list',
            params: {
              msno_view: user['msno'],
            },
          }).then(res => {
            var data = res.data;
            var chats = JSON.stringify(data['chats']);
            AsyncStorage.setItem('localChatList', chats).then(() => {
              AsyncStorage.setItem('remoteChatList', chats);
            });
          });
        }
      })
      .then(() => {
        this.listenMessageCheck().catch(e => alert(e));
      });
  };

  listenChatMessage = async () => {
    while (true) {
      await wait(2000).then(() => {
        AsyncStorage.getItem('chatContext').then(chatContextJson => {
          var chatContext = JSON.parse(chatContextJson);
          if (chatContext['msno'] > 0 && chatContext['chatMsno'] > 0) {
            axios
              .get('https://kkfriends.app/chat-message-after-id', {
                params: {
                  msno_view: chatContext['msno'],
                  msno_with: chatContext['chatMsno'],
                  id: chatContext['latestId'],
                },
              })
              .then(res => {
                var data = res.data;
                var messages = data['messages'];
                if (messages.length > 0) {
                  chatContext['messages'] = chatContext['messages'].concat(
                    messages,
                  );
                  chatContext['latestId'] = messages[messages.length - 1]['id'];
                  AsyncStorage.setItem(
                    'chatContext',
                    JSON.stringify(chatContext),
                  );
                }
              });
          }
        });
      });
    }
  };

  listenMessageCheck = async () => {
    while (true) {
      await wait(10000).then(() => {
        AsyncStorage.getItem('user').then(userData => {
          AsyncStorage.getItem('localChatList').then(localChatList => {
            var user = JSON.parse(userData);
            axios({
              method: 'get',
              url: 'https://kkfriends.app/chat-list',
              params: {
                msno_view: user['msno'],
              },
            }).then(res => {
              var data = res.data;
              var local = JSON.parse(localChatList);
              var remote = data['chats'];
              if (local && remote) {
                if (local.length > 0 && remote.length > 0) {
                  if (_.has(local[0], 'ts') && _.has(remote[0], 'ts')) {
                    if (
                      local[0]['ts'] !== remote[0]['ts'] &&
                      remote[0]['message_latest_msno'] !== user['msno']
                    ) {
                      AsyncStorage.setItem(
                        'localChatList',
                        JSON.stringify(remote),
                      ).then(res => {
                        showMessage({
                          message: '您有新訊息',
                          description: `${remote[0]['user_t']['name']} : ${remote[0]['message']}`,
                          type: 'info',
                        });
                      });
                    }
                  }
                }
              }
            });
          });
        });
      });
    }
  };

  render() {
    return (
      <React.Fragment>
        <IconRegistry icons={EvaIconsPack} />
        <ApplicationProvider mapping={mapping} theme={theme}>
          <AppNavigator />
          <FlashMessage position={'top'} />
        </ApplicationProvider>
      </React.Fragment>
    );
  }
}

export default App;
<file_sep>import React from 'react';
import {ActivityIndicator, StatusBar, View, AsyncStorage} from 'react-native';

export class AuthLoading extends React.Component {
  componentDidMount() {
    this.bootstrapAsync();
  }

  bootstrapAsync = async () => {
    const userToken = await AsyncStorage.getItem('user');
    this.props.navigation.navigate(userToken ? 'App' : 'Auth');
  };
  render() {
    return (
      <View>
        <ActivityIndicator />
        <StatusBar barStyle="default" />
      </View>
    );
  }
}
<file_sep>import React from 'react';
import {View} from 'react-native';
import {withStyles, Text} from 'react-native-ui-kitten';
import {ProfileParameter} from '../../profile/profileParameter';

import {ImageOverlay} from '../../common/imageOverlay';
import {textStyle} from '../../common/style';
import _ from 'lodash';

class ProfileInfoComponent extends React.Component {
  render() {
    const {themedStyle, profile} = this.props;

    return (
      <ImageOverlay
        style={themedStyle.container}
        source={{uri: profile.photo.imageSource}}>
        <View style={themedStyle.infoContainer}>
          <Text style={themedStyle.nameLabel} category="h2">
            {`${profile.firstName}\n${profile.lastName}`}
          </Text>
          <Text style={themedStyle.locationLabel} category="h6">
            {profile.location}
          </Text>
          <Text style={themedStyle.jobLabel} category="h6">
            {profile.job}
          </Text>
          <View style={themedStyle.parametersContainer}>
            <ProfileParameter
              hint="喜好藝人"
              value={`${profile.artists[0] ? profile.artists[0] : '<NAME>'}`}
            />
            <ProfileParameter
              hint="喜好類型"
              value={`${profile.categories[0]}`}
            />
          </View>
          <View style={themedStyle.parametersContainer}>
            <ProfileParameter
              hint="喜好歌曲"
              value={`${
                _.has(profile.currentFavSongs[0], 'name')
                  ? profile.currentFavSongs[0]['name']
                  : '全世界的朋友都讓我失望'
              }`}
            />
          </View>
        </View>
      </ImageOverlay>
    );
  }
}

export const ProfileInfo = withStyles(ProfileInfoComponent, theme => ({
  container: {
    flex: 1,
  },
  infoContainer: {
    position: 'absolute',
    paddingHorizontal: 24,
    paddingBottom: 32,
    left: 0,
    right: 0,
    bottom: 0,
  },
  parametersContainer: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    marginTop: 64,
  },
  nameLabel: {
    color: 'white',
    ...textStyle.headline,
  },
  locationLabel: {
    color: 'white',
    ...textStyle.headline,
  },
  jobLabel: {
    color: 'white',
    ...textStyle.headline,
  },
  rateHintLabel: {
    color: 'white',
  },
}));
<file_sep>import React from 'react';
import {Dimensions, View} from 'react-native';
import {withStyles, Text} from 'react-native-ui-kitten';
import {textStyle} from '../../components/common/style';
import {MessageContent} from './MessageContentComponent';

class LeftMessageComponent extends React.Component {
  render() {
    const {themedStyle, message, children} = this.props;

    return [
      <View style={themedStyle.cloudContainer} key={0}>
        <View style={[themedStyle.triangle, themedStyle.triangleLeft]} />
        <View style={[themedStyle.cloud, themedStyle.cloudLeft]}>
          <MessageContent message={message}>{children}</MessageContent>
        </View>
      </View>,
      <Text
        key={1}
        style={themedStyle.dateLabel}
        appearance="hint"
        category="c1">
        {message.date}
      </Text>,
    ];
  }
}

export const LeftMessage = withStyles(LeftMessageComponent, theme => ({
  triangle: {
    borderLeftWidth: 10,
    borderRightWidth: 10,
    borderBottomWidth: 15,
    borderLeftColor: 'transparent',
    borderRightColor: 'transparent',
    backgroundColor: 'transparent',
  },
  triangleLeft: {
    transform: [{rotate: '-90deg'}],
    borderBottomColor: theme['color-primary-default'],
  },
  cloudContainer: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  dateLabel: textStyle.caption1,
  cloud: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
    padding: 16,
    borderRadius: 8,
    maxWidth: Dimensions.get('window').width - 120,
  },
  cloudLeft: {
    left: -3,
    backgroundColor: theme['color-primary-default'],
    marginRight: 16,
  },
}));
<file_sep>import React from 'react';
import {View} from 'react-native';
import {Button, Text, withStyles} from 'react-native-ui-kitten';
import {SignInForm2} from '../components/SignInForm';
import {SocialAuth} from '../../auth/SocialAuth';
import {ScrollableAvoidKeyboard} from '../../common/scrollableAvoidKeyboard';
import {textStyle} from '../../common/style';
import {ImageOverlay} from '../../common/imageOverlay';

const imageSignIn4Bg = {
  imageSource: require('../../../../assets/img/julia-bg.jpg'),
};

class SignInComponent extends React.Component {
  state = {
    formData: undefined,
  };

  backgroundImage = imageSignIn4Bg;

  onForgotPasswordButtonPress = () => {
    this.props.onForgotPasswordPress();
  };

  onSignInButtonPress = () => {
    this.props.onSignInPress(this.state.formData);
  };

  onSignUpButtonPress = () => {
    this.props.onSignUpPress();
  };

  onGoogleButtonPress = () => {
    this.props.onGooglePress();
  };

  onFacebookButtonPress = () => {
    this.props.onFacebookPress();
  };

  onTwitterButtonPress = () => {
    this.props.onTwitterPress();
  };

  onFormDataChange = formData => {
    this.setState({formData});
  };

  render() {
    const {themedStyle} = this.props;

    return (
      <ScrollableAvoidKeyboard>
        <ImageOverlay
          style={themedStyle.container}
          source={this.backgroundImage.imageSource}>
          <View style={themedStyle.headerContainer}>
            <Text style={themedStyle.helloLabel} category="h1">
              Welcome to KKMeet
            </Text>
            <Text style={themedStyle.signInLabel} category="s1">
              Sign in to your account
            </Text>
          </View>
          <SignInForm2
            style={themedStyle.formContainer}
            onForgotPasswordPress={this.onForgotPasswordButtonPress}
            onDataChange={this.onFormDataChange}
          />
          <Button
            style={themedStyle.signInButton}
            textStyle={textStyle.button}
            size="giant"
            disabled={!this.state.formData}
            onPress={this.onSignInButtonPress}>
            SIGN IN
          </Button>
          <SocialAuth
            style={themedStyle.socialAuthContainer}
            iconStyle={themedStyle.socialAuthIcon}
            hint="Or Sign In using Social Media"
            onGooglePress={this.onGoogleButtonPress}
            onFacebookPress={this.onFacebookButtonPress}
            onTwitterPress={this.onTwitterButtonPress}
          />
          <Button
            style={themedStyle.signUpButton}
            textStyle={themedStyle.signUpText}
            appearance="ghost"
            activeOpacity={0.75}
            onPress={this.onSignUpButtonPress}>
            Don't have an account? Sign Up
          </Button>
        </ImageOverlay>
      </ScrollableAvoidKeyboard>
    );
  }
}

export const SignIn = withStyles(SignInComponent, theme => ({
  container: {
    flex: 1,
  },
  headerContainer: {
    minHeight: 216,
    justifyContent: 'center',
    alignItems: 'center',
  },
  formContainer: {
    flex: 1,
    paddingHorizontal: 16,
  },
  socialAuthContainer: {
    marginTop: 32,
  },
  helloLabel: {
    color: 'white',
    ...textStyle.headline,
  },
  signInLabel: {
    marginTop: 16,
    color: 'white',
    ...textStyle.subtitle,
  },
  socialAuthIcon: {
    tintColor: 'white',
  },
  signInButton: {
    marginHorizontal: 16,
  },
  signUpButton: {
    marginVertical: 12,
  },
  signUpText: {
    color: 'white',
    ...textStyle.subtitle,
  },
}));
<file_sep>import React from 'react';
import {AsyncStorage, View, ActivityIndicator, Dimensions} from 'react-native';
import {withStyles} from 'react-native-ui-kitten';
import {PARTNER_IMGS} from '../../../core/data/default';
import {ProfileInfo} from '../components/ProfileInfo';
import _ from 'lodash';

const default_songs = [
  {
    name: '全世界的朋友都讓我失望',
    album_id: 66519282,
    album_img_url: 'https://i.kfs.io/album/global/66519282,0v1/fit/300x300.jpg',
  },
];

class ProfileDemoComponent extends React.Component {
  state = {
    profile: {
      photo: {imageSource: ''},
      about: '',
      firstName: '',
      lastName: '',
      gender: '',
      age: 0,
      weight: 0,
      height: 0,
      job: '',
      inseam: 0,
      email: '',
      phoneNumber: '0',
      location: '',
      friends: [],
      online: true,
      categories: [],
      artists: [],
      currentFavSongs: [],
    },
    isLoaded: false,
  };

  componentDidMount = () => {
    AsyncStorage.getItem('profile').then(res => {
      var data = JSON.parse(res);
      var profile = {
        photo: _.has(PARTNER_IMGS, data['interlocutor']['msno'])
          ? {imageSource: PARTNER_IMGS[data['interlocutor']['msno']]}
          : data['interlocutor']['photo'],
        about: '',
        firstName: data['interlocutor']['firstName'],
        lastName: '',
        gender: data['interlocutor']['gender'],
        age: 0,
        weight: 0,
        height: 0,
        job: '',
        inseam: 0,
        email: data['interlocutor']['email'],
        phoneNumber: '0',
        location: 'Taipei, Taiwan',
        friends: [],
        online: true,
        categories: _.has(data, 'categories') ? data['categories'] : ['R&B'],
        artists: _.has(data, 'artists') ? data['artists'] : ['<NAME>'],
        currentFavSongs: _.has(data, 'currentFavSongs')
          ? data['currentFavSongs']
          : default_songs,
      };
      this.setState({profile: profile, isLoaded: true});
    });
  };

  onRateChange = value => {};

  render() {
    if (this.state.isLoaded === true) {
      return (
        <ProfileInfo
          profile={this.state.profile}
          onRateChange={this.onRateChange}
        />
      );
    } else {
      const {themedStyle} = this.props;
      return (
        <View style={themedStyle.loadContainer}>
          <ActivityIndicator size="large" />
        </View>
      );
    }
  }
}

export const ProfileDemo = withStyles(ProfileDemoComponent, theme => ({
  loadContainer: {
    height: Dimensions.get('window').height,
    width: Dimensions.get('window').width,
    justifyContent: 'center',
  },
}));
<file_sep>import React from 'react';
import {View} from 'react-native';
import {withStyles} from 'react-native-ui-kitten';
import {getContentAlignment} from './type';
import {getMessageContent} from './MessageContent';

class ChatMessageComponent extends React.Component {
  render() {
    const {alignment, style, message, children} = this.props;
    const flexStyle = getContentAlignment(alignment).style();
    const content = getMessageContent(alignment).view(message, children);

    return <View style={[flexStyle, style]}>{content}</View>;
  }
}

export const ChatMessage = withStyles(ChatMessageComponent, theme => ({}));
<file_sep>import React from 'react';
import {View} from 'react-native';
import {withStyles, List, Input, Icon} from 'react-native-ui-kitten';
import {Conversation} from '../../messages/Conversation';
import {textStyle} from '../../common/style';

const SearchIconOutline = style => <Icon name="search-outline" {...style} />;

class ChatListComponent extends React.Component {
  onConversation = index => {
    this.props.onConversation(index);
  };

  ponSearchStringChange = text => {
    this.props.onSearchStringChange(text);
  };

  renderItem = info => {
    const {themedStyle} = this.props;

    return (
      <Conversation
        style={themedStyle.item}
        conversation={info.item}
        index={info.index}
        onConversation={this.onConversation}
      />
    );
  };

  renderSearchInput = () => {
    const {themedStyle, searchEnabled} = this.props;

    return searchEnabled ? (
      <Input
        style={themedStyle.input}
        textStyle={textStyle.paragraph}
        icon={SearchIconOutline}
        placeholder="Search Interlocutor..."
        onChangeText={this.onSearchStringChange}
      />
    ) : null;
  };

  render() {
    const {themedStyle, conversations} = this.props;

    return (
      <View style={themedStyle.container}>
        {this.renderSearchInput()}
        <List
          style={themedStyle.container}
          data={conversations}
          renderItem={this.renderItem}
        />
      </View>
    );
  }
}

export const ChatList = withStyles(ChatListComponent, theme => ({
  container: {
    flex: 1,
    backgroundColor: theme['background-basic-color-2'],
  },
  item: {
    backgroundColor: theme['background-basic-color-1'],
    marginVertical: 0.5,
  },
  input: {
    marginHorizontal: 16,
    marginVertical: 16,
  },
}));
<file_sep>import React from 'react';
import {
  ScrollView,
  AsyncStorage,
  View,
  Alert,
  ActivityIndicator,
} from 'react-native';
import {SafeAreaView} from 'react-navigation';
import {categorisedProfileActivity1} from '../../../core/data/profile';
import {PARTNER_IMGS} from '../../../core/data/default';
import {ProfileHeader} from '../../profile/profileHeader';
import {Profile} from '../components/ProfilePage';
import axios from 'axios';
import _ from 'lodash';

const default_songs = [
  {
    name: '全世界的朋友都讓我失望',
    album_id: 66519282,
    album_img_url: 'https://i.kfs.io/album/global/66519282,0v1/fit/300x300.jpg',
  },
];

export class ProfilePageDemo extends React.Component {
  state = {
    profile: {},
    socials: {
      followers: 0,
      following: 0,
      friends: 0,
    },
    favorites: {
      artists: [],
      categories: [],
      currentFavSongs: [],
    },
    activity: categorisedProfileActivity1,
    liked: false,
    shared: false,
    isLoaded: false,
    isSelf: false,
    matched: false,
    coverPlayList: {},
    sharedPlayLists: {},
    modalVisible: false,
    modalIndex: 0,
    shareModalVisible: false,
  };

  static navigationOptions = ({navigation, screenProps}) => {
    const headerProps = {
      onBack: navigation.getParam('onBack', () => {}),
    };

    const header = navigationProps => {
      return <ProfileHeader {...navigationProps} {...headerProps} />;
    };

    return {...navigation, ...screenProps, header};
  };

  formatSharedPlayLists = sharedPlayLists => {
    var newSharedPlayLists = _.map(sharedPlayLists, playlist => {
      var newPlayList = {
        category: 'SharedPlayList',
        source: {
          imageSource: `https://i.kfs.io/album/global/${playlist['songs'][0]['album_id']},0v9/fit/300x300.jpg`,
        },
        playlistName: playlist['name'],
        songs: _.map(playlist['songs'], song => {
          var newSong = {
            songName: song['song_name'],
            source: {
              imageSource: `https://i.kfs.io/album/global/${song['album_id']},0v9/fit/300x300.jpg`,
            },
          };
          return newSong;
        }),
      };
      return newPlayList;
    });
    newSharedPlayLists = {
      ['與我分享']: newSharedPlayLists,
    };
    return newSharedPlayLists;
  };

  formatPlayList = playlist => {
    var newPlayList = _.map(playlist, song => {
      var formatSong = {
        category: 'MyPlayList',
        source: {imageSource: song['album_img_url']},
        songName: song['song_name'],
      };
      return formatSong;
    });
    newPlayList = {
      ['我的歌單']: newPlayList,
    };
    return newPlayList;
  };

  formatProfile = profile => {
    var newProfile = {
      photo: {
        imageSource: _.has(PARTNER_IMGS, profile['msno'])
          ? PARTNER_IMGS[profile['msno']]
          : profile['img_url'],
      },
      about: '',
      firstName: profile['name'],
      lastName: '',
      gender: profile['gender'],
      age: 0,
      weight: 0,
      height: 0,
      job: '',
      inseam: 0,
      email: profile['email'],
      phoneNumber: '0',
      location: 'Taipei, Taiwan',
      friends: [],
      online: true,
      msno: profile['msno'],
    };
    return newProfile;
  };

  getSocials = () => {
    axios({
      method: 'get',
      url: 'https://kkfriends.app/follow-list',
      params: {
        msno: this.props.navigation.getParam('msno'),
      },
    }).then(res => {
      var data = res.data;
      var friends = data['friends'];
      var followers = data['followed'];
      var following = data['following'];
      followers = followers.concat(friends);
      following = following.concat(friends);
      var socials = {
        followers: followers.length,
        following: following.length,
        friends: friends,
      };
      this.setState({socials: socials});
    });
  };

  componentDidMount() {
    this.props.navigation.setParams({
      onBack: this.onBackPress,
    });
    axios({
      method: 'get',
      url: 'https://kkfriends.app/user-profile',
      params: {
        msno_view: this.props.navigation.getParam('msnoView'),
        msno: this.props.navigation.getParam('msno'),
      },
    }).then(res => {
      AsyncStorage.getItem('profile').then(profile => {
        var selfProfile = JSON.parse(profile);
        var data = res.data;
        var user = data['user'];
        var coverPlayList = data['cover_playlist'];
        var favorites = data['profile'];
        var followStatus = data['follow_status'];
        var sharedPlayLists = data['shared_playlists'];
        sharedPlayLists = this.formatSharedPlayLists(sharedPlayLists);
        coverPlayList = this.formatPlayList(coverPlayList);
        user = this.formatProfile(user);
        selfProfile = selfProfile['interlocutor'];
        if (
          this.props.navigation.getParam('msnoView') ===
          this.props.navigation.getParam('msno')
        ) {
          this.setState({isSelf: true});
        }
        this.getSocials();
        this.getMyBoxPlaylists();
        this.setState({
          isLoaded: true,
          user: user,
          favorites: {
            artists: _.has(favorites, 'artists')
              ? favorites['artists']
              : ['<NAME>'],
            categories: _.has(favorites, 'categories')
              ? favorites['categories']
              : ['R&B'],
            current_fav_songs: _.has(favorites, 'current_fav_songs')
              ? favorites['current_fav_songs']
              : default_songs,
          },
          selfProfile: selfProfile,
          coverPlayList: coverPlayList,
          sharedPlayLists: sharedPlayLists,
          liked: followStatus['is_following'],
          matched: followStatus['is_friend'],
        });
      });
    });
  }

  getSharedPlayLists = () => {
    axios({
      method: 'get',
      url: 'https://kkfriends.app/user-profile',
      params: {
        msno: this.props.navigation.getParam('msno'),
        msno_view: this.props.navigation.getParam('msnoView'),
      },
    }).then(res => {
      var data = res.data;
      var sharedPlayLists = data['shared_playlists'];
      sharedPlayLists = this.formatSharedPlayLists(sharedPlayLists);
      this.setState({
        sharedPlayLists: sharedPlayLists,
      });
    });
  };

  getFollowStatus = () => {
    axios({
      method: 'get',
      url: 'https://kkfriends.app/user-profile',
      params: {
        msno_view: this.props.navigation.getParam('msnoView'),
        msno: this.props.navigation.getParam('msno'),
      },
    }).then(res => {
      var data = res.data;
      var followStatus = data['follow_status'];
      this.setState({matched: followStatus['is_friend']});
    });
  };

  onFollowPress = () => {
    if (this.state.liked === true) {
      axios({
        method: 'get',
        url: 'https://kkfriends.app/follower-unfollow',
        params: {
          msno_f: this.props.navigation.getParam('msnoView'),
          msno_t: this.props.navigation.getParam('msno'),
        },
      })
        .then(res => {
          this.setState({liked: false});
        })
        .then(() => {
          this.getSocials();
          this.getFollowStatus();
        });
    } else {
      axios({
        method: 'get',
        url: 'https://kkfriends.app/follower-follow',
        params: {
          msno_f: this.props.navigation.getParam('msnoView'),
          msno_t: this.props.navigation.getParam('msno'),
        },
      })
        .then(res => {
          this.setState({liked: true});
        })
        .then(() => {
          this.getSocials();
          this.getFollowStatus();
        });
    }
  };

  getMyBoxPlaylists = () => {
    axios({
      method: 'get',
      url: 'https://kkfriends.app/mybox-playlist-share',
      params: {
        msno: this.props.navigation.getParam('msnoView'),
        share_msno: this.props.navigation.getParam('msno'),
      },
    }).then(res => {
      var data = res.data;
      var playlists = data['playlists'];
      this.setState({myBoxPlayLists: playlists});
    });
  };

  addShareList = data => {
    var playlistID = data['playlistID'];
    axios({
      method: 'get',
      url: 'https://kkfriends.app/playlist-share-insert',
      params: {
        owner_msno: this.props.navigation.getParam('msnoView'),
        share_msno: this.props.navigation.getParam('msno'),
        playlist_id: playlistID,
      },
    }).then(res => {
      this.getSharedPlayLists();
    });
  };

  onPlayListSelected = option => {
    this.addShareList(option);
    if (option.isShared) {
      Alert.alert(option.label, '分享過囉!');
    } else {
      Alert.alert(option.label, '已分享!');
    }
  };

  onShareModalClose = () => {
    this.setState({shareModalVisible: false});
  };

  onSharedPlayListPress = index => {
    this.setState({modalIndex: index, modalVisible: true});
  };

  onSharePress = () => {
    this.setState({shareModalVisible: true});
  };

  onSwipeComplete = () => {
    this.setState({modalVisible: false});
  };

  handleNavigateBack = () => {};

  onMessagePress = () => {
    if (this.props.navigation.getParam('stack') === 'Discover') {
      this.props.navigation.push('DiscoverChatScreen', {
        msnoFrom: this.props.navigation.getParam('msnoView'),
        msnoTo: this.props.navigation.getParam('msno'),
        onNavigateBack: this.handleNavigateBack,
        stack: this.props.navigation.getParam('stack'),
        selfProfile: this.state.selfProfile,
        otherProfile: this.state.user,
      });
    } else if (this.props.navigation.getParam('stack') === 'Friends') {
      this.props.navigation.push('FriendChatScreen', {
        msnoFrom: this.props.navigation.getParam('msnoView'),
        msnoTo: this.props.navigation.getParam('msno'),
        onNavigateBack: this.handleNavigateBack,
        stack: this.props.navigation.getParam('stack'),
        selfProfile: this.state.selfProfile,
        otherProfile: this.state.user,
      });
    } else if (this.props.navigation.getParam('stack') === 'Chat') {
      this.props.navigation.push('ChatChatScreen', {
        msnoFrom: this.props.navigation.getParam('msnoView'),
        msnoTo: this.props.navigation.getParam('msno'),
        onNavigateBack: this.handleNavigateBack,
        stack: this.props.navigation.getParam('stack'),
        selfProfile: this.state.selfProfile,
        otherProfile: this.state.user,
      });
    } else {
    }
  };

  onBackPress = () => {
    this.props.navigation.state.params.onNavigateBack();
    this.props.navigation.goBack(null);
  };

  onFollowersPress = () => {
    if (this.props.navigation.getParam('stack') === 'Discover') {
      this.props.navigation.push('DiscoverFollowerScreen', {
        msnoView: this.props.navigation.getParam('msno'),
        isFollower: true,
        stack: this.props.navigation.getParam('stack'),
        onBack: this.onBackPress,
      });
    } else if (this.props.navigation.getParam('stack') === 'Chat') {
      this.props.navigation.push('ChatFollowerScreen', {
        msnoView: this.props.navigation.getParam('msno'),
        isFollower: true,
        stack: this.props.navigation.getParam('stack'),
        onBack: this.onBackPress,
      });
    } else if (this.props.navigation.getParam('stack') === 'Friends') {
      this.props.navigation.push('FriendFollowerScreen', {
        msnoView: this.props.navigation.getParam('msno'),
        isFollower: true,
        stack: this.props.navigation.getParam('stack'),
        onBack: this.onBackPress,
      });
    } else {
    }
  };

  onFollowingPress = () => {
    if (this.props.navigation.getParam('stack') === 'Discover') {
      this.props.navigation.push('DiscoverFollowingScreen', {
        msnoView: this.props.navigation.getParam('msno'),
        isFollowing: true,
        stack: this.props.navigation.getParam('stack'),
        onBack: this.onBackPress,
      });
    } else if (this.props.navigation.getParam('stack') === 'Chat') {
      this.props.navigation.push('ChatFollowingScreen', {
        msnoView: this.props.navigation.getParam('msno'),
        isFollowing: true,
        stack: this.props.navigation.getParam('stack'),
        onBack: this.onBackPress,
      });
    } else if (this.props.navigation.getParam('stack') === 'Friends') {
      this.props.navigation.push('FriendFollowingScreen', {
        msnoView: this.props.navigation.getParam('msno'),
        isFollowing: true,
        stack: this.props.navigation.getParam('stack'),
        onBack: this.onBackPress,
      });
    } else {
    }
  };

  onPostsPress = () => {};

  onPhotoPress = index => {};

  onActivityLikePress = index => {};

  render() {
    if (this.state.isLoaded === true) {
      return (
        // <SafeAreaView>
        <ScrollView showsVerticalScrollIndicator={false}>
          <Profile
            profile={this.state.user}
            socials={this.state.socials}
            favorites={this.state.favorites}
            coverPlayList={this.state.coverPlayList}
            activity={this.state.activity}
            sharedPlayLists={this.state.sharedPlayLists}
            myBoxPlayLists={this.state.myBoxPlayLists}
            onFollowPress={this.onFollowPress}
            onShareModalClose={this.onShareModalClose}
            onPlayListSelected={this.onPlayListSelected}
            onMessagePress={this.onMessagePress}
            onFollowersPress={this.onFollowersPress}
            onFollowingPress={this.onFollowingPress}
            onPostsPress={this.onPostsPress}
            onSharePress={this.onSharePress}
            onPhotoPress={this.onPhotoPress}
            onActivityLikePress={this.onActivityLikePress}
            onSharedPlayListPress={this.onSharedPlayListPress}
            onSwipeComplete={this.onSwipeComplete}
            modalVisible={this.state.modalVisible}
            shareModalVisible={this.state.shareModalVisible}
            modalIndex={this.state.modalIndex}
            liked={this.state.liked}
            shared={this.state.shared}
            matched={this.state.matched}
            isSelf={this.state.isSelf}
          />
        </ScrollView>
        // </SafeAreaView>
      );
    } else {
      return <View />;
    }
  }
}
<file_sep>import React from 'react';
import {Image} from 'react-native';
import {Avatar} from 'react-native-elements';
import {withStyles, Text} from 'react-native-ui-kitten';
import {textStyle} from '../common/style';

class ProfileActivityListItemComponent extends React.Component {
  render() {
    const {style, themedStyle, source, ...restProps} = this.props;

    return (
      <>
        <Avatar
          rounded
          style={[themedStyle.container, style]}
          // resizeMode="center"
          source={{uri: source.source.imageSource}}
          {...restProps}
        />
        <Text>{`${source.playlistName}`}</Text>
      </>
    );
  }
}

export const ProfileActivityListItem = withStyles(
  ProfileActivityListItemComponent,
  theme => ({
    container: {
      flexDirection: 'row',
      alignItems: 'center',
      justifyContent: 'space-between',
      padding: 16,
    },
    messageContainer: {
      // flex: 1,
    },
    leftSection: {
      flexDirection: 'row',
      alignItems: 'center',
    },
    avatar: {
      marginRight: 16,
    },
    userLabel: textStyle.subtitle,
    lastMessageLabel: textStyle.caption1,
    dateLabel: textStyle.paragraph,
    rightSection: {
      flexDirection: 'row',
      alignItems: 'center',
      justifyContent: 'flex-end',
    },
  }),
);
<file_sep>import React from 'react';
import {Dimensions, View} from 'react-native';
import {withStyles, Text} from 'react-native-ui-kitten';
import {textStyle} from '../common/style';
import {MessageContent} from './MessageContentComponent';

class RightMessageComponent extends React.Component {
  render() {
    const {themedStyle, message, children} = this.props;

    return [
      <Text
        key={0}
        style={themedStyle.dateLabel}
        appearance="hint"
        category="c1">
        {message.date}
      </Text>,
      <View style={themedStyle.cloudContainer} key={1}>
        <View style={[themedStyle.cloud, themedStyle.cloudRight]}>
          <MessageContent message={message}>{children}</MessageContent>
        </View>
        <View style={[themedStyle.triangle, themedStyle.triangleRight]} />
      </View>,
    ];
  }
}

export const RightMessage = withStyles(RightMessageComponent, theme => ({
  triangle: {
    borderLeftWidth: 10,
    borderRightWidth: 10,
    borderBottomWidth: 15,
    borderLeftColor: 'transparent',
    borderRightColor: 'transparent',
    backgroundColor: 'transparent',
  },
  triangleRight: {
    transform: [{rotate: '90deg'}],
    borderBottomColor: theme['text-hint-color'],
  },
  cloudContainer: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  dateLabel: textStyle.caption1,
  cloud: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
    padding: 16,
    borderRadius: 8,
    maxWidth: Dimensions.get('window').width - 120,
  },
  cloudRight: {
    left: 3,
    backgroundColor: theme['text-hint-color'],
    marginLeft: 16,
  },
}));
<file_sep>import React from 'react';
import {
  ScrollView,
  View,
  RefreshControl,
  AsyncStorage,
  ActivityIndicator,
  Dimensions,
} from 'react-native';
import {SafeAreaView} from 'react-navigation';
import Collapsible from 'react-native-collapsible';
import {CardList} from '../components/CardList';
import {Text, withStyles, Button, Icon, List} from 'react-native-ui-kitten';
import {textStyle} from '../../common/style';
import {PARTNER_IMGS} from '../../../core/data/default';
import axios from 'axios';
import _ from 'lodash';

const StarOutline = style => <Icon name="star-outline" {...style} />;

function wait(timeout) {
  return new Promise(resolve => {
    setTimeout(resolve, timeout);
  });
}

class DiscoverDemoComponent extends React.Component {
  state = {
    profiles: [],
    luckyPressCollapsed: true,
    refreshing: false,
    msnoView: '',
    isLoaded: false,
    isLuckyShotsLoaded: false,
    discoveries: [],
    luckyshots: [],
  };

  onItemPress = card => {
    this.props.navigation.push('DiscoverProfilePage', {
      msnoView: this.state.msnoView,
      msno: card['msno'],
      onNavigateBack: this.handleOnNavigateBack,
      stack: 'Discover',
    });
  };

  onShotItemPress = card => {
    this.props.navigation.push('DiscoverProfilePage', {
      msnoView: this.state.msnoView,
      onNavigateBack: this.handleOnNavigateBack,
      msno: card['msno'],
      stack: 'Discover',
    });
  };

  onLuckyPress = button => {
    axios({
      method: 'get',
      url: 'https://kkfriends.app/luckyshot',
      params: {
        msno: this.state.msnoView,
      },
    }).then(res => {
      var data = res.data;
      var luckyshots = data['data'];
      luckyshots = this.formatLuckyShots(luckyshots);
      if (this.state.luckyPressCollapsed === true) {
        this.setState({
          luckyPressCollapsed: false,
          isLuckyShotsLoaded: true,
          luckyshots: luckyshots,
        });
      }
    });
  };

  formatLuckyShots = luckyshots => {
    var newShots = _.map(luckyshots, shot => {
      var newShot = {
        photo: {
          imageSource: `https://i.kfs.io/album/global/${shot['album_id']},0v9/fit/300x300.jpg`,
        },
        firstName: shot['song_name'],
        lastName: '',
        job: '',
        inseam: 0,
        email: '',
        phoneNumber: '',
        location: '',
        friends: [],
        online: true,
        msno: shot['luckyshot_msno'],
      };
      return newShot;
    });
    return newShots;
  };

  componentDidMount = () => {
    AsyncStorage.getItem('user').then(res => {
      var data = JSON.parse(res);
      var msnoView = data['msno'];
      this.setState({msnoView: msnoView});
      this.getDiscover(msnoView);
    });
  };

  getDiscover = msno => {
    axios({
      method: 'get',
      url: 'https://kkfriends.app/discovery-list',
      params: {msno: msno},
    }).then(res => {
      var data = res.data;
      var discoveries = data['discoveries'];
      this.setState({discoveries: discoveries, isLoaded: true});
    });
  };

  formatUsers = users => {
    var newUsers = _.map(users, user => {
      var newUser = {
        photo: {
          imageSource: _.has(PARTNER_IMGS, user['msno'])
            ? PARTNER_IMGS[user['msno']]
            : user['img_url'],
        },
        about: '',
        firstName: user['name'],
        lastName: '',
        gender: user['gender'],
        age: 0,
        weight: 0,
        height: 0,
        job: '',
        inseam: 0,
        email: user['email'],
        phoneNumber: '0',
        location: 'Taipei, Taiwan',
        friends: [],
        online: true,
        msno: user['msno'],
      };
      return newUser;
    });
    return newUsers;
  };

  handleOnNavigateBack = () => {};

  renderItem = info => {
    const {themedStyle} = this.props;
    const users = this.formatUsers(info.item['users']);
    return (
      <>
        <Text style={themedStyle.pagerLabel} category="h3">
          {`${info.item['reason']}`}
        </Text>
        <CardList
          profiles={users}
          onItemPress={this.onItemPress}
          onItemLikePress={this.onItemLikePress}
          onItemCommentPress={this.onItemCommentPress}
        />
      </>
    );
  };

  onRefresh = () => {
    this.setState({refreshing: true});
    this.componentDidMount();
    this.setState({refreshing: false, luckyPressCollapsed: true});
  };

  onItemLikePress = card => {};

  onItemCommentPress = card => {};

  render() {
    const {themedStyle} = this.props;
    if (this.state.isLoaded === true) {
      return (
        <SafeAreaView
          style={themedStyle.safeAreaContainer}
          forceInset={{bottom: 'never'}}>
          <ScrollView
            contentContainerStyle={themedStyle.container}
            refreshControl={
              <RefreshControl
                refreshing={this.state.refreshing}
                onRefresh={this.onRefresh}
              />
            }>
            {this.state.luckyPressCollapsed ? (
              <View style={themedStyle.buttonSection}>
                <Button
                  icon={StarOutline}
                  style={themedStyle.button}
                  textStyle={textStyle.button}
                  onPress={this.onLuckyPress}>
                  Lucky Shot
                </Button>
              </View>
            ) : null}
            <Collapsible
              style={themedStyle.container}
              collapsed={this.state.luckyPressCollapsed}>
              <Text style={themedStyle.pagerLabel} category="h3">
                Lucky Shot
              </Text>
              <CardList
                profiles={this.state.luckyshots}
                onItemPress={this.onShotItemPress}
                onItemLikePress={this.onItemLikePress}
                onItemCommentPress={this.onItemCommentPress}
              />
            </Collapsible>
            <List
              style={themedStyle.container}
              data={this.state.discoveries}
              renderItem={this.renderItem}
            />
          </ScrollView>
        </SafeAreaView>
      );
    } else {
      return (
        <View style={themedStyle.loadContainer}>
          <ActivityIndicator size="large" />
        </View>
      );
    }
  }
}

export const DiscoverDemo = withStyles(DiscoverDemoComponent, theme => ({
  container: {
    paddingVertical: 8,
    backgroundColor: theme['background-basic-color-2'],
  },
  safeAreaContainer: {
    backgroundColor: theme['background-basic-color-2'],
  },
  loadContainer: {
    height: Dimensions.get('window').height,
    width: Dimensions.get('window').width,
    justifyContent: 'center',
  },
  buttonSection: {
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: theme['background-basic-color-2'],
  },
  button: {
    flex: 1,
    width: 200,
  },
  pagerLabel: {
    paddingHorizontal: 16,
    marginVertical: 16,
    ...textStyle.paragraph,
  },
}));
<file_sep>import React from 'react';
import {ImageBackground, StyleSheet, View} from 'react-native';
import {withStyles} from 'react-native-ui-kitten';

class ImageOverlayComponent extends React.Component {
  getOverlayColor = source => {
    const {themedStyle} = this.props;

    return source || themedStyle.overlay.backgroundColor;
  };

  render() {
    const {style, themedStyle, children, ...restProps} = this.props;
    // @ts-ignore: overlayColor (additional style property)
    const {
      overlayColor: derivedOverlayColor,
      ...containerStyle
    } = StyleSheet.flatten(style);

    const overlayColor = this.getOverlayColor(derivedOverlayColor);

    return (
      <ImageBackground style={containerStyle} {...restProps}>
        <View style={[themedStyle.overlay, {backgroundColor: overlayColor}]} />
        {children}
      </ImageBackground>
    );
  }
}

export const ImageOverlay = withStyles(ImageOverlayComponent, theme => ({
  overlay: {
    backgroundColor: 'rgba(0, 0, 0, 0.45)',
    ...StyleSheet.absoluteFillObject,
  },
}));
<file_sep>import React from 'react';
import {
  ScrollView,
  View,
  AsyncStorage,
  ActivityIndicator,
  Dimensions,
} from 'react-native';
import {SafeAreaView} from 'react-navigation';
import {Text, withStyles, Button, Icon} from 'react-native-ui-kitten';
import MaterialCardWithRightButtons from '../../radio/MaterialCardWithRightButtons';
import {ProfilePlayList} from '../../radio/profilePlayList';
import {textStyle} from '../../common/style';
import axios from 'axios';
import _ from 'lodash';

const StarOutline = style => <Icon name="star-outline" {...style} />;

function wait(timeout) {
  return new Promise(resolve => {
    setTimeout(resolve, timeout);
  });
}

class RadioDemoComponent extends React.Component {
  state = {
    isLoaded: false,
    playlist: [],
  };

  componentDidMount = () => {
    AsyncStorage.getItem('user').then(res => {
      var user = JSON.parse(res);
      this.getRadio(user['msno']);
      this.props.navigation.addListener('willFocus', () => {
        this.getRadio(user['msno']);
      });
    });
  };

  getRadio = msno => {
    axios({
      method: 'get',
      url: 'https://kkfriends.app/radio',
      params: {
        msno: msno,
      },
    }).then(res => {
      var data = res.data;
      var playlist = data['playlist'];
      playlist = this.formatRadio(playlist);
      this.setState({playlist: playlist, isLoaded: true});
    });
  };

  formatRadio = playlist => {
    var newPlayList = _.map(playlist, song => {
      var newSong = {
        category: 'Radio',
        source: {imageSource: song['album_img_url']},
        name: song['song_name'],
        from_user: song['from_user'],
      };
      return newSong;
    });
    newPlayList = {
      ['朋友組成電台']: newPlayList,
    };
    return newPlayList;
  };

  onPhotoPress = () => {};

  renderMyPlayListElement = source => {
    return Object.keys(source).map(category => {
      if (category === '朋友組成電台') {
        const categoryActivities = source[category];

        return this.renderSongElement(category, categoryActivities);
      }
    });
  };

  renderSongElement = (category, activities) => {
    const {themedStyle} = this.props;
    return (
      <View style={themedStyle.radioListContainer} key={category}>
        <ProfilePlayList data={activities} onItemPress={this.onPhotoPress} />
      </View>
    );
  };

  render() {
    const {themedStyle} = this.props;
    if (this.state.isLoaded === true) {
      return (
        <SafeAreaView forceInset={{bottom: 'never'}}>
          <ScrollView contentContainerStyle={themedStyle.container}>
            <View style={themedStyle.radioContainer}>
              <MaterialCardWithRightButtons
                style={themedStyle.materialCardWithRightButtons}
                playlist={this.state.playlist}></MaterialCardWithRightButtons>
            </View>
            <Text style={themedStyle.pagerLabel} category="h3">
              朋友組成電台
            </Text>
            {this.renderMyPlayListElement(this.state.playlist)}
          </ScrollView>
        </SafeAreaView>
      );
    } else {
      return (
        <View style={themedStyle.loadContainer}>
          <ActivityIndicator size="large" />
        </View>
      );
    }
  }
}

export const RadioDemo = withStyles(RadioDemoComponent, theme => ({
  container: {
    paddingHorizontal: 16,
    paddingVertical: 8,
    backgroundColor: theme['background-basic-color-2'],
  },
  loadContainer: {
    height: Dimensions.get('window').height,
    width: Dimensions.get('window').width,
    justifyContent: 'center',
  },
  radioListContainer: {
    flex: 1,
  },
  button: {
    flex: 1,
    width: 200,
  },
  pagerLabel: {
    marginVertical: 16,
    ...textStyle.paragraph,
  },
  radioContainer: {
    justifyContent: 'center',
    alignItems: 'center',
  },
  materialCardWithRightButtons: {
    width: 328,
    height: 266,
    borderRadius: 25,
  },
}));
<file_sep>import React from 'react';
import {
  createAppContainer,
  SafeAreaView,
  createSwitchNavigator,
} from 'react-navigation';
import {createBottomTabNavigator} from 'react-navigation-tabs';
import {createStackNavigator} from 'react-navigation-stack';
import {
  BottomNavigation,
  BottomNavigationTab,
  Layout,
  Text,
  Icon,
} from 'react-native-ui-kitten';
import {ProfileDemo} from './screens/containers/ProfileDemo';
import {DiscoverDemo} from './screens/containers/DiscoverDemo';
import {ChatListDemo} from './screens/containers/ChatListDemo';
import {ChatDemoComponent} from './screens/containers/ChatDemo';
import {ProfilePageDemo} from './screens/containers/ProfilePageDemo';
import {FriendListDemo} from './screens/containers/FriendListDemo';
import {RadioDemo} from './screens/containers/RadioDemo';
import {AuthDemo} from './screens/containers/AuthDemo';
import {AuthLoading} from './screens/components/AuthLoading';

// React Navigation also requires installing additional dependencies:
//
// npm i react-navigation react-navigation-tabs react-native-reanimated react-native-gesture-handler
//
// Then install it for ios:
//
// cd ios && pod install

const TabBarComponent = ({navigation}) => {
  const onSelect = index => {
    const {[index]: selectedTabRoute} = navigation.state.routes;
    navigation.navigate(selectedTabRoute.routeName);
  };

  const ProfileIcon = style => <Icon name="person-outline" {...style} />;

  const CompassIcon = style => <Icon name="compass-outline" {...style} />;

  const FriendIcon = style => <Icon name="people-outline" {...style} />;

  const ChatIcon = style => <Icon name="message-circle-outline" {...style} />;

  const RadioIcon = style => <Icon name="radio-outline" {...style} />;

  return (
    <SafeAreaView forceInset={{bottom: 'always', top: 'never'}}>
      <BottomNavigation
        selectedIndex={navigation.state.index}
        onSelect={onSelect}>
        <BottomNavigationTab title="Profile" icon={ProfileIcon} />
        <BottomNavigationTab title="Discover" icon={CompassIcon} />
        <BottomNavigationTab title="Friends" icon={FriendIcon} />
        <BottomNavigationTab title="Chat" icon={ChatIcon} />
        <BottomNavigationTab title="Radio" icon={RadioIcon} />
      </BottomNavigation>
    </SafeAreaView>
  );
};

const ChatStack = createStackNavigator({
  ChatList: {
    screen: ChatListDemo,
    navigationOptions: {headerShown: false},
  },
  ChatChatScreen: {
    screen: ChatDemoComponent,
  },
  ChatProfilePage: {
    screen: ProfilePageDemo,
  },
  ChatFollowingScreen: {
    screen: FriendListDemo,
  },
  ChatFollowerScreen: {
    screen: FriendListDemo,
  },
});

ChatStack.navigationOptions = ({navigation}) => {
  if (navigation.state.index !== 0) {
    var tabBarVisible = false;
  } else {
    var tabBarVisible = true;
  }
  return {tabBarVisible};
};

const DiscoverStack = createStackNavigator({
  Discover: {screen: DiscoverDemo, navigationOptions: {headerShown: false}},
  DiscoverProfilePage: {
    screen: ProfilePageDemo,
  },
  DiscoverChatScreen: {
    screen: ChatDemoComponent,
  },
  DiscoverFollowingScreen: {
    screen: FriendListDemo,
  },
  DiscoverFollowerScreen: {
    screen: FriendListDemo,
  },
});

DiscoverStack.navigationOptions = ({navigation}) => {
  if (navigation.state.index !== 0) {
    var tabBarVisible = false;
  } else {
    var tabBarVisible = true;
  }
  return {tabBarVisible};
};

const FriendsStack = createStackNavigator({
  Friends: {screen: FriendListDemo, navigationOptions: {headerShown: false}},
  FriendProfilePage: {
    screen: ProfilePageDemo,
  },
  FriendChatScreen: {
    screen: ChatDemoComponent,
  },
  FriendFollowingScreen: {
    screen: FriendListDemo,
  },
  FriendFollowerScreen: {
    screen: FriendListDemo,
  },
});

FriendsStack.navigationOptions = ({navigation}) => {
  if (navigation.state.index !== 0) {
    var tabBarVisible = false;
  } else {
    var tabBarVisible = true;
  }
  return {tabBarVisible};
};

const TabNavigator = createBottomTabNavigator(
  {
    Profile: ProfileDemo,
    Discover: DiscoverStack,
    Friends: FriendsStack,
    Chat: ChatStack,
    Radio: RadioDemo,
  },
  {
    tabBarComponent: TabBarComponent,
    initialRouteName: 'Discover',
  },
);

const AuthStack = createStackNavigator({
  Auth: {screen: AuthDemo, navigationOptions: {headerShown: false}},
});
const AppStack = createStackNavigator({
  App: {screen: TabNavigator, navigationOptions: {headerShown: false}},
});
const AppNavigatorStack = createSwitchNavigator(
  {
    AuthLoadingScreen: AuthLoading,
    Auth: {screen: AuthStack},
    App: AppStack,
  },
  {initialRouteName: 'AuthLoadingScreen'},
);

export const AppNavigator = createAppContainer(AppNavigatorStack);
<file_sep>import React from 'react';
import {
  ScrollView,
  AsyncStorage,
  View,
  ActivityIndicator,
  Dimensions,
} from 'react-native';
import {Divider} from 'react-native-elements';
import {SafeAreaView} from 'react-navigation';
import {FriendList} from '../components/FriendList';
import {PARTNER_IMGS} from '../../../core/data/default';
import {FriendListHeader} from '../../friends/friendListHeader';
import {withStyles, Text} from 'react-native-ui-kitten';
import {textStyle} from '../../common/style';
import axios from 'axios';
import _ from 'lodash';

class FriendListDemoComponent extends React.Component {
  state = {
    // friends: conversations,
    searchEnabled: false,
    followers: [],
    following: [],
    friends: [],
    isLoaded: false,
  };

  static navigationOptions = ({navigation, screenProps}) => {
    const headerProps = {
      onBack: navigation.getParam('onBack'),
    };

    const header = navigationProps => {
      return navigation.state.routeName === 'Friends' ? null : (
        <FriendListHeader {...navigationProps} {...headerProps} />
      );
    };

    return {...navigation, ...screenProps, header};
  };

  componentDidMount = () => {
    this.props.navigation.addListener('willFocus', () => {
      if (this.props.navigation.state.routeName === 'Friends') {
        this.getFriendList();
      }
    });
    AsyncStorage.getItem('user').then(res => {
      var data = JSON.parse(res);
      var msnoView = data['msno'];
      this.setState({msnoView: msnoView});
    });
    if (this.props.navigation.getParam('isFollowing') === true) {
      axios({
        method: 'get',
        url: 'https://kkfriends.app/follow-list',
        params: {
          msno: this.props.navigation.getParam('msnoView'),
        },
      }).then(res => {
        var data = res.data;
        var friends = data['friends'];
        var following = data['following'];
        following = this.formatFollowList(following);
        friends = this.formatFollowList(friends);
        var followingList = following.concat(friends);
        this.setState({following: followingList, isLoaded: true});
      });
    } else if (this.props.navigation.getParam('isFollower') === true) {
      axios({
        method: 'get',
        url: 'https://kkfriends.app/follow-list',
        params: {
          msno: this.props.navigation.getParam('msnoView'),
        },
      }).then(res => {
        var data = res.data;
        var friends = data['friends'];
        var followers = data['followed'];
        followers = this.formatFollowList(followers);
        friends = this.formatFollowList(friends);
        var followedList = followers.concat(friends);
        this.setState({followers: followedList, isLoaded: true});
      });
    } else {
      this.getFriendList();
    }
  };

  getFriendList = () => {
    AsyncStorage.getItem('user').then(res => {
      var user = JSON.parse(res);
      axios({
        method: 'get',
        url: 'https://kkfriends.app/follow-list',
        params: {
          msno: user['msno'],
        },
      }).then(res => {
        var data = res.data;
        var friends = data['friends'];
        var followers = data['followed'];
        var following = data['following'];
        friends = this.formatFollowList(friends);
        followers = this.formatFollowList(followers);
        following = this.formatFollowList(following);
        this.setState({
          followers: followers,
          following: following,
          friends: friends,
          isLoaded: true,
        });
      });
    });
  };

  formatFollowList = followList => {
    var newFollowList = _.map(followList, user => {
      var newUser = {
        interlocutor: {
          photo: {
            imageSource: _.has(PARTNER_IMGS, user['msno'])
              ? PARTNER_IMGS[user['msno']]
              : user['img_url'],
          },
          about: '',
          firstName: user['name'],
          lastName: '',
          gender: user['gender'],
          age: 0,
          weight: 0,
          height: 0,
          job: '',
          inseam: 0,
          email: user['email'],
          phoneNumber: '0',
          location: 'Taipei, Taiwan',
          friends: [],
          online: true,
          msno: user['msno'],
        },
      };
      return newUser;
    });
    return newFollowList;
  };

  handleOnNavigateBack = () => {
    AsyncStorage.getItem('user').then(res => {
      var user = JSON.parse(res);
      this.getFriendList(user['msno']);
    });
  };

  onProfileFollowingPress = index => {
    var profile = this.state.following[index]['interlocutor'];
    if (this.props.navigation.getParam('isFollower') === true) {
      if (this.props.navigation.getParam('stack') === 'Discover') {
        this.props.navigation.push('DiscoverProfilePage', {
          msnoView: this.state.msnoView,
          msno: profile['msno'],
          stack: this.props.navigation.getParam('stack'),
          // onNavigateBack: this.handleOnNavigateBack,
          onNavigateBack: () => {},
          isFollower: true,
        });
      } else if (this.props.navigation.getParam('stack') === 'Chat') {
        this.props.navigation.push('ChatProfilePage', {
          msnoView: this.state.msnoView,
          msno: profile['msno'],
          stack: this.props.navigation.getParam('stack'),
          // onNavigateBack: this.handleOnNavigateBack,
          onNavigateBack: () => {},
          isFollower: true,
        });
      } else {
        this.props.navigation.push('FriendProfilePage', {
          msnoView: this.state.msnoView,
          msno: profile['msno'],
          stack: 'Friends',
          // onNavigateBack: this.handleOnNavigateBack,
          onNavigateBack: () => {},
          isFollower: true,
        });
      }
    } else if (this.props.navigation.getParam('isFollowing') === true) {
      if (this.props.navigation.getParam('stack') === 'Discover') {
        this.props.navigation.push('DiscoverProfilePage', {
          msnoView: this.state.msnoView,
          msno: profile['msno'],
          stack: this.props.navigation.getParam('stack'),
          onNavigateBack: () => {},
          isFollowing: true,
        });
      } else if (this.props.navigation.getParam('stack') === 'Chat') {
        this.props.navigation.push('ChatProfilePage', {
          msnoView: this.state.msnoView,
          msno: profile['msno'],
          stack: this.props.navigation.getParam('stack'),
          // onNavigateBack: this.handleOnNavigateBack,
          onNavigateBack: () => {},
          isFollowing: true,
        });
      } else {
        this.props.navigation.push('FriendProfilePage', {
          msnoView: this.state.msnoView,
          msno: profile['msno'],
          stack: 'Friends',
          // onNavigateBack: this.handleOnNavigateBack,
          onNavigateBack: () => {},
          isFollowing: true,
        });
      }
    } else {
      if (this.props.navigation.getParam('stack') === 'Discover') {
        this.props.navigation.push('DiscoverProfilePage', {
          msnoView: this.state.msnoView,
          msno: profile['msno'],
          onNavigateBack: this.handleOnNavigateBack,
          stack: this.props.navigation.getParam('stack'),
        });
      } else if (this.props.navigation.getParam('stack') === 'Chat') {
        this.props.navigation.push('ChatProfilePage', {
          msnoView: this.state.msnoView,
          msno: profile['msno'],
          onNavigateBack: this.handleOnNavigateBack,
          stack: this.props.navigation.getParam('stack'),
        });
      } else {
        this.props.navigation.push('FriendProfilePage', {
          msnoView: this.state.msnoView,
          msno: profile['msno'],
          onNavigateBack: this.handleOnNavigateBack,
          stack: 'Friends',
        });
      }
    }
  };

  onProfileFollowerPress = index => {
    var profile = this.state.followers[index]['interlocutor'];
    if (this.props.navigation.getParam('isFollower') === true) {
      if (this.props.navigation.getParam('stack') === 'Discover') {
        this.props.navigation.push('DiscoverProfilePage', {
          msnoView: this.state.msnoView,
          msno: profile['msno'],
          stack: this.props.navigation.getParam('stack'),
          // onNavigateBack: this.handleOnNavigateBack,
          onNavigateBack: () => {},
          isFollower: true,
        });
      } else if (this.props.navigation.getParam('stack') === 'Chat') {
        this.props.navigation.push('ChatProfilePage', {
          msnoView: this.state.msnoView,
          msno: profile['msno'],
          stack: this.props.navigation.getParam('stack'),
          // onNavigateBack: this.handleOnNavigateBack,
          onNavigateBack: () => {},
          isFollower: true,
        });
      } else {
        this.props.navigation.push('FriendProfilePage', {
          msnoView: this.state.msnoView,
          msno: profile['msno'],
          stack: 'Friends',
          // onNavigateBack: this.handleOnNavigateBack,
          onNavigateBack: () => {},
          isFollower: true,
        });
      }
    } else if (this.props.navigation.getParam('isFollowing') === true) {
      if (this.props.navigation.getParam('stack') === 'Discover') {
        this.props.navigation.push('DiscoverProfilePage', {
          msnoView: this.state.msnoView,
          msno: profile['msno'],
          stack: this.props.navigation.getParam('stack'),
          onNavigateBack: () => {},
          isFollowing: true,
        });
      } else if (this.props.navigation.getParam('stack') === 'Chat') {
        this.props.navigation.push('ChatProfilePage', {
          msnoView: this.state.msnoView,
          msno: profile['msno'],
          stack: this.props.navigation.getParam('stack'),
          // onNavigateBack: this.handleOnNavigateBack,
          onNavigateBack: () => {},
          isFollowing: true,
        });
      } else {
        this.props.navigation.push('FriendProfilePage', {
          msnoView: this.state.msnoView,
          msno: profile['msno'],
          stack: 'Friends',
          // onNavigateBack: this.handleOnNavigateBack,
          onNavigateBack: () => {},
          isFollowing: true,
        });
      }
    } else {
      if (this.props.navigation.getParam('stack') === 'Discover') {
        this.props.navigation.push('DiscoverProfilePage', {
          msnoView: this.state.msnoView,
          msno: profile['msno'],
          onNavigateBack: this.handleOnNavigateBack,
          stack: this.props.navigation.getParam('stack'),
        });
      } else if (this.props.navigation.getParam('stack') === 'Chat') {
        this.props.navigation.push('ChatProfilePage', {
          msnoView: this.state.msnoView,
          msno: profile['msno'],
          onNavigateBack: this.handleOnNavigateBack,
          stack: this.props.navigation.getParam('stack'),
        });
      } else {
        this.props.navigation.push('FriendProfilePage', {
          msnoView: this.state.msnoView,
          msno: profile['msno'],
          onNavigateBack: this.handleOnNavigateBack,
          stack: 'Friends',
        });
      }
    }
  };

  onProfilePress = index => {
    if (this.props.navigation.getParam('isFollower') === true) {
      var profile = this.state.followers[index]['interlocutor'];
    } else if (this.props.navigation.getParam('isFollowing') === true) {
      var profile = this.state.following[index]['interlocutor'];
    } else {
      var profile = this.state.friends[index]['interlocutor'];
    }
    if (this.props.navigation.getParam('isFollower') === true) {
      if (this.props.navigation.getParam('stack') === 'Discover') {
        this.props.navigation.push('DiscoverProfilePage', {
          msnoView: this.state.msnoView,
          msno: profile['msno'],
          stack: this.props.navigation.getParam('stack'),
          // onNavigateBack: this.handleOnNavigateBack,
          onNavigateBack: () => {},
          isFollower: true,
        });
      } else if (this.props.navigation.getParam('stack') === 'Chat') {
        this.props.navigation.push('ChatProfilePage', {
          msnoView: this.state.msnoView,
          msno: profile['msno'],
          stack: this.props.navigation.getParam('stack'),
          // onNavigateBack: this.handleOnNavigateBack,
          onNavigateBack: () => {},
          isFollower: true,
        });
      } else {
        this.props.navigation.push('FriendProfilePage', {
          msnoView: this.state.msnoView,
          msno: profile['msno'],
          stack: 'Friends',
          // onNavigateBack: this.handleOnNavigateBack,
          onNavigateBack: () => {},
          isFollower: true,
        });
      }
    } else if (this.props.navigation.getParam('isFollowing') === true) {
      if (this.props.navigation.getParam('stack') === 'Discover') {
        this.props.navigation.push('DiscoverProfilePage', {
          msnoView: this.state.msnoView,
          msno: profile['msno'],
          stack: this.props.navigation.getParam('stack'),
          onNavigateBack: () => {},
          isFollowing: true,
        });
      } else if (this.props.navigation.getParam('stack') === 'Chat') {
        this.props.navigation.push('ChatProfilePage', {
          msnoView: this.state.msnoView,
          msno: profile['msno'],
          stack: this.props.navigation.getParam('stack'),
          // onNavigateBack: this.handleOnNavigateBack,
          onNavigateBack: () => {},
          isFollowing: true,
        });
      } else {
        this.props.navigation.push('FriendProfilePage', {
          msnoView: this.state.msnoView,
          msno: profile['msno'],
          stack: 'Friends',
          // onNavigateBack: this.handleOnNavigateBack,
          onNavigateBack: () => {},
          isFollowing: true,
        });
      }
    } else {
      if (this.props.navigation.getParam('stack') === 'Discover') {
        this.props.navigation.push('DiscoverProfilePage', {
          msnoView: this.state.msnoView,
          msno: profile['msno'],
          onNavigateBack: this.handleOnNavigateBack,
          stack: this.props.navigation.getParam('stack'),
        });
      } else if (this.props.navigation.getParam('stack') === 'Chat') {
        this.props.navigation.push('ChatProfilePage', {
          msnoView: this.state.msnoView,
          msno: profile['msno'],
          onNavigateBack: this.handleOnNavigateBack,
          stack: this.props.navigation.getParam('stack'),
        });
      } else {
        this.props.navigation.push('FriendProfilePage', {
          msnoView: this.state.msnoView,
          msno: profile['msno'],
          onNavigateBack: this.handleOnNavigateBack,
          stack: 'Friends',
        });
      }
    }
  };

  onMessagePress = index => {
    AsyncStorage.getItem('profile').then(res => {
      var selfProfile = JSON.parse(res);
      if (this.props.navigation.getParam('isFollower') === true) {
        var profile = this.state.followers[index]['interlocutor'];
      } else if (this.props.navigation.getParam('isFollowing') === true) {
        var profile = this.state.following[index]['interlocutor'];
      } else {
        var profile = this.state.friends[index]['interlocutor'];
      }
      selfProfile = selfProfile['interlocutor'];
      this.props.navigation.push('FriendChatScreen', {
        msnoFrom: this.state.msnoView,
        msnoTo: profile['msno'],
        selfProfile: selfProfile,
        otherProfile: profile,
        onNavigateBack: this.handleOnNavigateBack,
        stack: 'Friends',
      });
    });
  };

  render() {
    if (this.state.isLoaded === true) {
      if (this.props.navigation.getParam('isFollower') === true) {
        return (
          <SafeAreaView forceInset={{bottom: 'never', top: 'never'}}>
            <ScrollView>
              <FriendList
                searchEnabled={this.state.searchEnabled}
                friends={this.state.followers}
                onProfile={this.onProfilePress}
                onMessagePress={this.onMessagePress}
                isFollow={true}
              />
            </ScrollView>
          </SafeAreaView>
        );
      } else if (this.props.navigation.getParam('isFollowing') === true) {
        return (
          <SafeAreaView forceInset={{top: 'never'}}>
            <ScrollView>
              <FriendList
                searchEnabled={this.state.searchEnabled}
                friends={this.state.following}
                onProfile={this.onProfilePress}
                onMessagePress={this.onMessagePress}
                isFollow={true}
              />
            </ScrollView>
          </SafeAreaView>
        );
      } else {
        const {themedStyle} = this.props;
        return (
          <SafeAreaView forceInset={{bottom: 'never'}}>
            <ScrollView>
              <Text style={themedStyle.pagerLabel}>朋友清單</Text>
              <FriendList
                searchEnabled={this.state.searchEnabled}
                friends={this.state.friends}
                onProfile={this.onProfilePress}
                onMessagePress={this.onMessagePress}
                isFollow={false}
              />
              <Divider />
              <Text style={themedStyle.pagerLabel}>我追隨的人</Text>
              <FriendList
                searchEnabled={this.state.searchEnabled}
                friends={this.state.following}
                onProfile={this.onProfileFollowingPress}
                onMessagePress={this.onMessagePress}
                isFollow={true}
              />
              <Divider />
              <Text style={themedStyle.pagerLabel}>追隨我的人</Text>
              <FriendList
                searchEnabled={this.state.searchEnabled}
                friends={this.state.followers}
                onProfile={this.onProfileFollowerPress}
                onMessagePress={this.onMessagePress}
                isFollow={true}
              />
            </ScrollView>
          </SafeAreaView>
        );
      }
    } else {
      const {themedStyle} = this.props;
      return (
        <View style={themedStyle.loadContainer}>
          <ActivityIndicator size="large" />
        </View>
      );
    }
  }
}

export const FriendListDemo = withStyles(FriendListDemoComponent, theme => ({
  loadContainer: {
    height: Dimensions.get('window').height,
    width: Dimensions.get('window').width,
    justifyContent: 'center',
  },
  pagerLabel: {
    paddingHorizontal: 16,
    marginVertical: 16,
    ...textStyle.paragraph,
  },
}));
<file_sep>import React from 'react';
import {
  withStyles,
  Avatar,
  TopNavigation,
  TopNavigationAction,
  Icon,
} from 'react-native-ui-kitten';
import {SafeAreaView} from 'react-navigation';

const ArrowIosBackFill = style => {
  return <Icon {...style} name="arrow-ios-back" />;
};

class FriendListHeaderComponent extends React.Component {
  onBack = () => {
    this.props.onBack();
  };

  //   onProfile = () => {
  //     const {interlocutor, onProfile} = this.props;

  //     onProfile(interlocutor);
  //   };

  renderLeftControl = () => {
    return (
      <TopNavigationAction icon={ArrowIosBackFill} onPress={this.onBack} />
    );
  };

  //   renderProfileAvatar = () => {
  //     const {interlocutor} = this.props;

  //     return <Avatar source={interlocutor.photo.imageSource} />;
  //   };

  //   renderRightControls = () => {
  //     const {themedStyle} = this.props;

  //     return (
  //       <TopNavigationAction
  //         icon={this.renderProfileAvatar}
  //         onPress={this.onProfile}
  //       />
  //     );
  //   };

  //   renderInterlocutorProps = () => {
  //     const {interlocutor, lastSeen} = this.props;

  //     return (
  //       interlocutor && {
  //         title: `${interlocutor.firstName} ${interlocutor.lastName}`,
  //         subtitle: `Last seen ${lastSeen}`,
  //         rightControls: this.renderRightControls(),
  //       }
  //     );
  //   };

  render() {
    const {themedStyle} = this.props;

    return (
      <SafeAreaView
        forceInset={{bottom: 'never'}}
        style={themedStyle.container}>
        <TopNavigation
          alignment="center"
          leftControl={this.renderLeftControl()}
          //   {...this.renderInterlocutorProps()}
        />
      </SafeAreaView>
    );
  }
}

export const FriendListHeader = withStyles(
  FriendListHeaderComponent,
  theme => ({
    container: {
      backgroundColor: theme['background-basic-color-1'],
    },
  }),
);
<file_sep>import React from 'react';
import {AsyncStorage, View} from 'react-native';
import {ChatHeader} from '../../messages/ChatHeader';
import {Chat} from '../components/Chat';
import axios from 'axios';
import _ from 'lodash';
import moment from 'moment';

function wait(timeout) {
  return new Promise(resolve => {
    setTimeout(resolve, timeout);
  });
}

export class ChatDemoComponent extends React.Component {
  state = {
    newMessageText: '',
    realConversation: {
      interlocutor: '',
      lastSeen: '',
      messages: [],
    },
  };

  static navigationOptions = ({navigation, screenProps}) => {
    const headerProps = {
      interlocutor: navigation.getParam('interlocutor'),
      lastSeen: navigation.getParam('lastSeen', 'today'),
      onBack: navigation.getParam('onBack', () => {}),
      onProfile: navigation.getParam('onProfile', () => {}),
    };

    const header = navigationProps => {
      return <ChatHeader {...navigationProps} {...headerProps} />;
    };

    return {...navigation, ...screenProps, header};
  };

  // checkNewMessages = async () => {
  //   axios
  //     .get('https://kkfriends.app/chat-message-before-id', {
  //       params: {
  //         msno_view: this.props.navigation.getParam('msnoFrom'),
  //         msno_with: this.props.navigation.getParam('msnoTo'),
  //         id: 9999999999,
  //       },
  //     })
  //     .then(res => {
  //       var data = res.data;
  //       var messages = data['messages'];
  //     });
  // };

  syncMessages = () => {
    AsyncStorage.getItem('chatContext').then(chatContextJson => {
      var chatContext = JSON.parse(chatContextJson);
      if (
        chatContext['messages'].length !==
        this.state.realConversation['messages'].length
      ) {
        var messages = chatContext['messages'];
        var formatMessages = _.map(messages, msg => {
          var date = moment(msg['ts'] * 1000);
          formatDate = date.format('HH:mm A');
          var formatMsg = {
            author:
              msg['msno_f'] === this.props.navigation.getParam('msnoFrom')
                ? this.props.navigation.getParam('selfProfile')
                : this.props.navigation.getParam('otherProfile'),
            text: msg['message'],
            date: formatDate,
            ts: date,
            read: true,
            delivered: true,
          };
          return formatMsg;
        });
        if (formatMessages.length !== 0) {
          var newestMsg = formatMessages[0];
          var formatConversation = {
            interlocutor: this.props.navigation.getParam('otherProfile'),
            lastSeen: newestMsg.ts.fromNow(),
            messages: formatMessages,
          };
          this.props.navigation.setParams({
            interlocutor: formatConversation.interlocutor,
            lastSeen: formatConversation.lastSeen,
            onBack: this.onBackPress,
            onProfile: this.onProfilePress,
          });
          this.setState({
            realConversation: formatConversation,
          });
        } else {
        }
      } else if (
        chatContext['messages'].length ===
          this.state.realConversation['messages'].length &&
        this.state.realConversation['messages'].length === 0
      ) {
        this.props.navigation.setParams({
          interlocutor: this.props.navigation.getParam('otherProfile'),
          onBack: this.onBackPress,
          onProfile: this.onProfilePress,
        });
      } else {
      }
    });
  };

  callChatAPI = () => {
    axios
      .get('https://kkfriends.app/chat-message-before-id', {
        params: {
          msno_view: this.props.navigation.getParam('msnoFrom'),
          msno_with: this.props.navigation.getParam('msnoTo'),
          id: 9999999999,
        },
      })
      .then(res => {
        var data = res.data;
        var messages = data['messages'];

        AsyncStorage.setItem(
          'chatContext',
          JSON.stringify({
            chatMsno: this.props.navigation.getParam('msnoTo'),
            msno: this.props.navigation.getParam('msnoFrom'),
            latestId: messages.length > 0 ? messages[0]['id'] : 0,
            messages: messages.reverse(),
          }),
        ).then(() => {
          this.syncMessages();
        });
      });
  };

  handleOnNavigateBack = () => {};

  componentDidMount() {
    this.callChatAPI();
    this.syncView();
  }

  syncView = async () => {
    while (true) {
      await wait(2000).then(() => {
        this.syncMessages();
      });
    }
  };

  onProfilePress = profile => {
    if (this.props.navigation.getParam('stack') === 'Discover') {
      this.props.navigation.push('DiscoverProfilePage', {
        msnoView: this.props.navigation.getParam('msnoFrom'),
        msno: this.props.navigation.getParam('msnoTo'),
        onNavigateBack: this.handleOnNavigateBack,
        stack: this.props.navigation.getParam('stack'),
      });
    } else if (this.props.navigation.getParam('stack') === 'Chat') {
      this.props.navigation.push('ChatProfilePage', {
        msnoView: this.props.navigation.getParam('msnoFrom'),
        msno: this.props.navigation.getParam('msnoTo'),
        onNavigateBack: this.handleOnNavigateBack,
        stack: this.props.navigation.getParam('stack'),
      });
    } else if (this.props.navigation.getParam('stack') === 'Friends') {
      this.props.navigation.push('FriendProfilePage', {
        msnoView: this.props.navigation.getParam('msnoFrom'),
        msno: this.props.navigation.getParam('msnoTo'),
        onNavigateBack: this.handleOnNavigateBack,
        stack: this.props.navigation.getParam('stack'),
      });
    } else {
    }
  };

  onNewMessageChange = newMessageText => {
    this.setState({newMessageText});
  };

  onMessageAddPress = () => {
    var dateNow = moment(Date.now());
    var dateFormat = dateNow.format('HH:mm A');
    const newMessage = {
      author: this.props.navigation.getParam('selfProfile'),
      text: this.state.newMessageText,
      date: dateFormat,
      ts: dateNow,
      read: false,
      delivered: false,
    };
    const conversationCopy = this.state.realConversation;
    conversationCopy.messages.push(newMessage);
    axios({
      method: 'post',
      url: 'https://kkfriends.app/chat-post-message',
      data: {
        msno_f: this.props.navigation.getParam('msnoFrom'),
        msno_t: this.props.navigation.getParam('msnoTo'),
        message: this.state.newMessageText,
      },
    }).then(res => {
      this.setState({
        realConversation: conversationCopy,
        newMessageText: '',
      });
    });
  };

  onBackPress = () => {
    AsyncStorage.setItem(
      'chatContext',
      JSON.stringify({
        chatMsno: 0,
        msno: 0,
        latestId: 0,
        messages: [],
      }),
    ).then(() => {
      this.props.navigation.state.params.onNavigateBack();
      this.props.navigation.goBack(null);
    });
  };

  render() {
    return (
      <Chat
        selfProfile={this.props.navigation.getParam('selfProfile')}
        otherProfile={this.props.navigation.getParam('otherProfile')}
        conversation={this.state.realConversation}
        newMessage={this.state.newMessageText}
        onNewMessageChange={this.onNewMessageChange}
        onMessageAdd={this.onMessageAddPress}
      />
    );
  }
}
<file_sep>import React from 'react';
import {withStyles, Icon} from 'react-native-ui-kitten';

const DoneAllIconOutline = style => <Icon name="done-all-outline" {...style} />;

const messageIcons = {
  ['read']: {
    icon(style) {
      return DoneAllIconOutline({
        ...style.messageIndicatorIcon,
        ...style.messageIndicatorIconRead,
      });
    },
  },
  ['delivered']: {
    icon(style) {
      return DoneAllIconOutline({
        ...style.messageIndicatorIcon,
        ...style.messageIndicatorIconDelivered,
      });
    },
  },
};

export class MessageIconComponent extends React.Component {
  defineMessageStatus(read, delivered) {
    if (read) {
      return 'read';
    } else if (delivered && !read) {
      return 'delivered';
    } else {
      return null;
    }
  }

  render() {
    const {themedStyle, message} = this.props;

    const messageStatus = this.defineMessageStatus(
      message.read,
      message.delivered,
    );
    const iconProvider = messageIcons[messageStatus];

    return iconProvider ? iconProvider.icon(themedStyle) : null;
  }
}

export const MessageIcon = withStyles(MessageIconComponent, theme => ({
  messageIndicatorIcon: {
    width: 13,
    height: 8,
    marginRight: 4,
  },
  messageIndicatorIconRead: {
    tintColor: theme['color-primary-default'],
  },
  messageIndicatorIconDelivered: {
    tintColor: theme['text-hint-color'],
  },
}));
<file_sep>import React from 'react';
import {TouchableOpacity} from 'react-native';
import {Text, withStyles} from 'react-native-ui-kitten';
import {DiscoverActivityBar} from '../../discover/discoverActivityBar';
import {DiscoverTips} from '../../discover/discoverTips';
import {ImageOverlay} from '../../common/imageOverlay';
import {textStyle} from '../../common/style';

class CardListItemComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      filled: false,
    };
    this.onLikeButtonPress = this.onLikeButtonPress.bind(this);
  }

  onPress = () => {
    this.props.onPress(this.props.profile);
  };

  onCommentsButtonPress = () => {
    this.props.onCommentPress(this.props.profile);
  };

  onLikeButtonPress = () => {
    if (this.state.filled === true) {
      this.setState({filled: false});
    } else {
      this.setState({filled: true});
    }
    this.props.onLikePress(this.props.profile);
  };

  render() {
    const {style, themedStyle, profile, ...restProps} = this.props;

    return (
      <TouchableOpacity
        activeOpacity={0.9}
        {...restProps}
        style={[themedStyle.container, style]}
        onPress={this.onPress}>
        <ImageOverlay
          style={themedStyle.image}
          source={{uri: profile.photo.imageSource}}>
          <Text style={themedStyle.titleLabel} category="h4">
            {`${profile.firstName} ${profile.lastName}`}
          </Text>
          <DiscoverTips style={themedStyle.tipsContainer}>
            {`${profile.job}`}
          </DiscoverTips>
          <DiscoverActivityBar
            style={themedStyle.activityContainer}
            textStyle={themedStyle.activityBarLabel}
            comments={0}
            likes={profile.likes}
            filled={this.state.filled}
            onCommentPress={this.onCommentsButtonPress}
            onLikePress={this.onLikeButtonPress}
          />
        </ImageOverlay>
      </TouchableOpacity>
    );
  }
}

export const CardListItem = withStyles(CardListItemComponent, theme => ({
  container: {
    minHeight: 300,
    borderRadius: 12,
    overflow: 'hidden',
  },
  tipsContainer: {
    marginTop: 16,
  },
  activityContainer: {
    marginTop: 48,
  },
  image: {
    flex: 1,
    paddingHorizontal: 16,
    paddingTop: 24,
    paddingBottom: 16,
  },
  titleLabel: {
    maxWidth: 192,
    color: 'white',
    ...textStyle.headline,
  },
  activityBarLabel: {
    color: 'white',
  },
}));
<file_sep>import React from 'react';
import {withStyles} from 'react-native-ui-kitten';

import {ActivityBar} from '../common/activityBar';
import {CommentsButton} from '../common/commentsButton';
import {LikeButton} from '../common/likeButton';
import {ReactionBar} from '../common/reactionBar';

class DiscoverActivityBarComponent extends React.Component {
  render() {
    const {
      themedStyle,
      textStyle,
      comments,
      likes,
      filled,
      onCommentPress,
      onLikePress,
      children,
      ...restProps
    } = this.props;

    return (
      <ActivityBar {...restProps}>
        {children}
        <ReactionBar>
          {/* <CommentsButton
            textStyle={textStyle}
            activeOpacity={0.75}
            onPress={onCommentPress}>
            {`${comments}`}
          </CommentsButton> */}
          {/* <LikeButton
            textStyle={textStyle}
            activeOpacity={0.75}
            filled={filled}
            onPress={onLikePress}>
            {`${likes}`}
          </LikeButton> */}
        </ReactionBar>
      </ActivityBar>
    );
  }
}

export const DiscoverActivityBar = withStyles(
  DiscoverActivityBarComponent,
  theme => ({}),
);
<file_sep>export const profile = {
  photo: {imageSource: require('../../../assets/img/sean.jpg')},
  about:
    "Hi! My name is Sean. I'm 41 and I live in Taipei." +
    " I'm interested in photography, coding.",
  firstName: 'Sean',
  lastName: 'Chang',
  gender: 'Male',
  age: 27,
  weight: 60,
  height: 176,
  job: 'Data Scientist',
  email: '<EMAIL>',
  phoneNumber: '+886 980648096',
  location: 'Taipei, Taiwan.',
  friends: [profile1, profile2],
  onLine: false,
};

export const profiles = [profile, profile, profile];

export const profile1 = {
  photo: {imageSource: require('../../../assets/img/bot.png')},
  about:
    "Hi! My name is Jen. I'm 41 and I live in Atlanta." +
    " I'm interested in swag, rap.",
  firstName: 'Bot',
  lastName: '',
  gender: 'Female',
  age: 25,
  weight: 48,
  height: 174,
  job: 'Bot',
  inseam: 44,
  email: '<EMAIL>',
  phoneNumber: '+375 44 123 12 12',
  location: 'Berlin, Germany',
  friends: [profile, profile2],
  onLine: false,
};

export const profile2 = {
  photo: {imageSource: require('../../../assets/img/bot.png')},
  about:
    "Hi! My name is Jen. I'm 41 and I live in Atlanta." +
    " I'm interested in swag, rap.",
  firstName: 'Bot',
  lastName: '',
  gender: 'Female',
  age: 25,
  weight: 48,
  height: 174,
  job: 'Bot',
  inseam: 44,
  email: '<EMAIL>',
  phoneNumber: '+375 44 123 12 12',
  location: 'Berlin, Germany',
  friends: [profile, profile1],
  onLine: false,
};

export const profile3 = {
  photo: {imageSource: require('../../../assets/img/bot.png')},
  about:
    "Hi! My name is Jen. I'm 41 and I live in Atlanta." +
    " I'm interested in swag, rap.",
  firstName: 'Bot',
  lastName: '',
  gender: 'Female',
  age: 25,
  weight: 48,
  height: 174,
  job: 'Bot',
  inseam: 44,
  email: '<EMAIL>',
  phoneNumber: '+375 44 123 12 12',
  location: 'Berlin, Germany',
  friends: [profile, profile2],
  onLine: false,
};

export const profile4 = {
  photo: {imageSource: require('../../../assets/img/bot.png')},
  about:
    "Hi! My name is Jen. I'm 41 and I live in Atlanta." +
    " I'm interested in swag, rap.",
  firstName: 'Bot',
  lastName: '',
  gender: 'Female',
  age: 25,
  weight: 48,
  height: 174,
  job: 'Bot',
  inseam: 44,
  email: '<EMAIL>',
  phoneNumber: '+375 44 123 12 12',
  location: 'Berlin, Germany',
  friends: [profile, profile2],
  onLine: false,
};

export const profile5 = {
  photo: {imageSource: require('../../../assets/img/bot.png')},
  about:
    "Hi! My name is Jen. I'm 41 and I live in Atlanta." +
    " I'm interested in swag, rap.",
  firstName: 'Bot',
  lastName: '',
  gender: 'Female',
  age: 25,
  weight: 48,
  height: 174,
  job: 'Bot',
  inseam: 44,
  email: '<EMAIL>',
  phoneNumber: '+375 44 123 12 12',
  location: 'Berlin, Germany',
  friends: [profile, profile2],
  onLine: false,
};

export const profile6 = {
  photo: {imageSource: require('../../../assets/img/bot.png')},
  about:
    "Hi! My name is Jen. I'm 41 and I live in Atlanta." +
    " I'm interested in swag, rap.",
  firstName: 'Bot',
  lastName: '',
  gender: 'Female',
  age: 25,
  weight: 48,
  height: 174,
  job: 'Bot',
  inseam: 44,
  email: '<EMAIL>',
  phoneNumber: '+375 44 123 12 12',
  location: 'Berlin, Germany',
  friends: [profile, profile2],
  onLine: false,
};

export const profile7 = {
  photo: {imageSource: require('../../../assets/img/bot.png')},
  about:
    "Hi! My name is Jen. I'm 41 and I live in Atlanta." +
    " I'm interested in swag, rap.",
  firstName: 'Bot',
  lastName: '',
  gender: 'Female',
  age: 25,
  weight: 48,
  height: 174,
  job: 'Bot',
  inseam: 44,
  email: '<EMAIL>',
  phoneNumber: '+375 44 123 12 12',
  location: 'Berlin, Germany',
  friends: [profile, profile2],
  onLine: false,
};

export const profile8 = {
  photo: {imageSource: require('../../../assets/img/bot.png')},
  about:
    "Hi! My name is Jen. I'm 41 and I live in Atlanta." +
    " I'm interested in swag, rap.",
  firstName: 'Bot',
  lastName: '',
  gender: 'Female',
  age: 25,
  weight: 48,
  height: 174,
  job: 'Bot',
  inseam: 44,
  email: '<EMAIL>',
  phoneNumber: '+375 44 123 12 12',
  location: 'Berlin, Germany',
  friends: [profile, profile2],
  onLine: false,
};

export const profile9 = {
  photo: {imageSource: require('../../../assets/img/bot.png')},
  about:
    "Hi! My name is Jen. I'm 41 and I live in Atlanta." +
    " I'm interested in swag, rap.",
  firstName: 'Bot',
  lastName: '',
  gender: 'Female',
  age: 25,
  weight: 48,
  height: 174,
  job: 'Bot',
  inseam: 44,
  email: '<EMAIL>',
  phoneNumber: '+375 44 123 12 12',
  location: 'Berlin, Germany',
  friends: [profile, profile2],
  onLine: false,
};

export const profile10 = {
  photo: {imageSource: require('../../../assets/img/bot.png')},
  about:
    "Hi! My name is Jen. I'm 41 and I live in Atlanta." +
    " I'm interested in swag, rap.",
  firstName: 'Bot',
  lastName: '',
  gender: 'Female',
  age: 25,
  weight: 48,
  height: 174,
  job: 'Bot',
  inseam: 44,
  email: '<EMAIL>',
  phoneNumber: '+375 44 123 12 12',
  location: 'Berlin, Germany',
  friends: [profile, profile2],
  onLine: false,
};

export const profileSocials1 = {
  followers: 1500,
  following: 86,
  posts: 116,
};

export const profileFavorites = {
  artists: ['Julia'],
  categories: ['R&B'],
};

export const categorisedProfileActivity1 = {
  ['與我分享']: [
    {
      category: 'Sharing',
      source: {
        imageSource: require('../../../assets/img/image-feed-travel-1.jpg'),
      },
    },
    {
      category: 'Sharing',
      source: {
        imageSource: require('../../../assets/img/image-feed-travel-1.jpg'),
      },
    },
    {
      category: 'Sharing',
      source: {
        imageSource: require('../../../assets/img/image-feed-travel-1.jpg'),
      },
    },
    {
      category: 'Sharing',
      source: {
        imageSource: require('../../../assets/img/image-feed-travel-1.jpg'),
      },
    },
    {
      category: 'Sharing',
      source: {
        imageSource: require('../../../assets/img/image-feed-travel-1.jpg'),
      },
    },
  ],
  ['我的歌單']: [
    {
      category: 'MyPlayList',
      source: {
        imageSource: require('../../../assets/img/sean.jpg'),
      },
    },
    {
      category: 'MyPlayList',
      source: {
        imageSource: require('../../../assets/img/sean.jpg'),
      },
    },
    {
      category: 'MyPlayList',
      source: {
        imageSource: require('../../../assets/img/sean.jpg'),
      },
    },
    {
      category: 'MyPlayList',
      source: {
        imageSource: require('../../../assets/img/sean.jpg'),
      },
    },
    {
      category: 'MyPlayList',
      source: {
        imageSource: require('../../../assets/img/sean.jpg'),
      },
    },
  ],
  // ['Style']: [
  //   {
  //     category: 'Style',
  //     source: {
  //       imageSource: require('../../../assets/img/image-feed-travel-1.jpg'),
  //     },
  //   },
  //   {
  //     category: 'Style',
  //     source: {
  //       imageSource: require('../../../assets/img/image-feed-travel-1.jpg'),
  //     },
  //   },
  //   {
  //     category: 'Style',
  //     source: {
  //       imageSource: require('../../../assets/img/image-feed-travel-1.jpg'),
  //     },
  //   },
  //   {
  //     category: 'Style',
  //     source: {
  //       imageSource: require('../../../assets/img/image-feed-travel-1.jpg'),
  //     },
  //   },
  //   {
  //     category: 'Style',
  //     source: {
  //       imageSource: require('../../../assets/img/image-feed-travel-1.jpg'),
  //     },
  //   },
  // ],
};
<file_sep>import React from 'react';
import {View} from 'react-native';
import {withStyles} from 'react-native-ui-kitten';

class ReactionBarComponent extends React.Component {
  render() {
    const {themedStyle, style, ...restProps} = this.props;

    return <View {...restProps} style={[themedStyle.container, style]} />;
  }
}

export const ReactionBar = withStyles(ReactionBarComponent, theme => ({
  container: {
    flexDirection: 'row',
  },
}));
<file_sep>import React from 'react';
import {LeftMessage} from './LeftMessage';
import {RightMessage} from './RightMessage';

const messageContents = {
  ['row-left']: {
    view(message, children) {
      return <LeftMessage message={message}>{children}</LeftMessage>;
    },
  },
  ['row-right']: {
    view(message, children) {
      return <RightMessage message={message}>{children}</RightMessage>;
    },
  },
};

export function getMessageContent(alignment) {
  return messageContents[alignment];
}
<file_sep>import React from 'react';
import {View} from 'react-native';
import {withStyles, List, ListItem} from 'react-native-ui-kitten';
import {ProfilePlayListItem} from './profilePlayListItem';

// @ts-ignore (override `renderItem` prop)

class ProfilePlayListComponent extends React.Component {
  onItemPress = index => {
    this.props.onItemPress(index);
  };

  renderItem = info => {
    const {themedStyle} = this.props;

    return (
      <ProfilePlayListItem
        style={[themedStyle.item]}
        song={info.item}
        onPress={this.onItemPress}
      />
    );
  };

  render() {
    const {contentContainerStyle, themedStyle, ...restProps} = this.props;

    return (
      <View style={themedStyle.container}>
        <List
          showsHorizontalScrollIndicator={false}
          {...restProps}
          contentContainerStyle={[themedStyle.container, contentContainerStyle]}
          renderItem={this.renderItem}
        />
      </View>
    );
  }
}

export const ProfilePlayList = withStyles(ProfilePlayListComponent, theme => ({
  container: {},
  itemContainer: {
    paddingHorizontal: 0,
    paddingVertical: 0,
    marginHorizontal: 8,
    borderRadius: 8,
    overflow: 'hidden',
  },
  item: {
    // width: 120,
    // height: 100,
    marginVertical: 0.5,
  },
}));
<file_sep>const containerRow = {
  flexDirection: 'row',
  alignItems: 'center',
};

const placements = {
  ['row-left']: {
    style() {
      return {
        ...containerRow,
        justifyContent: 'flex-start',
      };
    },
  },

  ['row-right']: {
    style() {
      return {
        ...containerRow,
        justifyContent: 'flex-end',
      };
    },
  },
};

export function getContentAlignment(value) {
  return placements[value];
}<file_sep>import React from 'react';
import {View} from 'react-native';
import {withStyles, Button, Icon} from 'react-native-ui-kitten';
import {textStyle} from '../../common/style';
import {ValidationInput} from '../../common/validationInput';
import {NameValidator, PasswordValidator} from '../../../core/validators';

const EyeOffIconFill = style => {
  return <Icon {...style} name="eye-off" />;
};

const PersonIconFill = style => {
  return <Icon {...style} name="person" />;
};

class SignInForm2Component extends React.Component {
  state = {
    username: undefined,
    password: <PASSWORD>,
  };

  componentDidUpdate(prevProps, prevState) {
    const oldFormValid = this.isValid(prevState);
    const newFormValid = this.isValid(this.state);

    const isStateChanged = this.state !== prevState;
    const becomeValid = !oldFormValid && newFormValid;
    const becomeInvalid = oldFormValid && !newFormValid;
    const remainValid = oldFormValid && newFormValid;

    if (becomeValid) {
      this.props.onDataChange(this.state);
    } else if (becomeInvalid) {
      this.props.onDataChange(undefined);
    } else if (isStateChanged && remainValid) {
      this.props.onDataChange(this.state);
    }
  }

  onForgotPasswordButtonPress = () => {
    this.props.onForgotPasswordPress();
  };

  onUsernameInputTextChange = username => {
    this.setState({username});
  };

  onPasswordInputTextChange = password => {
    this.setState({password});
  };

  isValid = value => {
    const {username, password} = value;

    return username !== undefined && password !== undefined;
  };

  render() {
    const {style, themedStyle, ...restProps} = this.props;

    return (
      <View style={[themedStyle.container, style]} {...restProps}>
        <View style={themedStyle.formContainer}>
          <ValidationInput
            textStyle={textStyle.paragraph}
            placeholder="User Name"
            icon={PersonIconFill}
            validator={NameValidator}
            onChangeText={this.onUsernameInputTextChange}
          />
          <ValidationInput
            style={themedStyle.passwordInput}
            textStyle={textStyle.paragraph}
            placeholder="<PASSWORD>"
            icon={EyeOffIconFill}
            secureTextEntry={true}
            validator={PasswordValidator}
            onChangeText={this.onPasswordInputTextChange}
          />
          <View style={themedStyle.forgotPasswordContainer}>
            <Button
              style={themedStyle.forgotPasswordButton}
              textStyle={themedStyle.forgotPasswordText}
              appearance="ghost"
              activeOpacity={0.75}
              onPress={this.onForgotPasswordButtonPress}>
              Forgot your password?
            </Button>
          </View>
        </View>
      </View>
    );
  }
}

export const SignInForm2 = withStyles(SignInForm2Component, theme => ({
  container: {},
  forgotPasswordContainer: {
    flexDirection: 'row',
    justifyContent: 'flex-end',
  },
  passwordInput: {
    marginTop: 16,
  },
  forgotPasswordButton: {
    paddingHorizontal: 0,
  },
  forgotPasswordText: {
    fontSize: 15,
    color: theme['text-hint-color'],
    ...textStyle.subtitle,
  },
}));
<file_sep>import React from 'react';
import {ImageProps, View, ViewProps} from 'react-native';
import {withStyles, Text} from 'react-native-ui-kitten';
import {textStyle} from '../common/style';

class DiscoverTipsComponent extends React.Component {
  renderIconElement = style => {
    return this.props.icon(style);
  };

  render() {
    const {style, themedStyle, icon, children} = this.props;

    return (
      <View style={[themedStyle.container, style]}>
        {icon ? this.renderIconElement(themedStyle.icon) : null}
        <Text style={themedStyle.text}>{children}</Text>
      </View>
    );
  }
}

export const DiscoverTips = withStyles(DiscoverTipsComponent, theme => ({
  container: {
    flexDirection: 'row',
  },
  icon: {
    width: 20,
    height: 20,
    marginRight: 18,
    tintColor: 'white',
  },
  text: {
    color: 'white',
    ...textStyle.subtitle,
  },
}));
<file_sep>import React, {Component} from 'react';
import {StyleSheet, View, Image, TouchableOpacity, Text} from 'react-native';
import MaterialCommunityIconsIcon from 'react-native-vector-icons/MaterialCommunityIcons';

export default class MaterialCardWithRightButtons extends React.Component {
  state = {
    playing: false,
    currentIndex: 0,
    playlist: this.props.playlist,
    image: this.props.playlist['朋友組成電台'][0]['source']['imageSource'],
    songName: this.props.playlist['朋友組成電台'][0]['name'],
  };

  onNext = () => {
    if (this.state.currentIndex < this.state.playlist['朋友組成電台'].length) {
      this.setState({
        currentIndex: this.state.currentIndex + 1,
        image: this.state.playlist['朋友組成電台'][this.state.currentIndex + 1][
          'source'
        ]['imageSource'],
        songName: this.state.playlist['朋友組成電台'][
          this.state.currentIndex + 1
        ]['name'],
      });
    }
  };

  onPrevious = () => {
    if (this.state.currentIndex < this.state.playlist['朋友組成電台'].length) {
      this.setState({
        currentIndex: this.state.currentIndex + 1,
        image: this.state.playlist['朋友組成電台'][this.state.currentIndex - 1][
          'source'
        ]['imageSource'],
        songName: this.state.playlist['朋友組成電台'][
          this.state.currentIndex - 1
        ]['name'],
      });
    }
  };

  setPlaying = () => {
    if (this.state.playing === true) {
      this.setState({playing: false});
    } else {
      this.setState({playing: true});
    }
  };

  render() {
    return (
      <View style={[styles.container, this.props.style]}>
        <Image
          source={{uri: this.state.image}}
          style={styles.cardItemImagePlace}></Image>
        <View style={styles.buttonGroup}>
          <TouchableOpacity style={styles.leftBtn} onPress={this.onPrevious}>
            <MaterialCommunityIconsIcon
              name="skip-previous"
              style={styles.icon1}></MaterialCommunityIconsIcon>
          </TouchableOpacity>
          {this.state.playing ? (
            <TouchableOpacity
              style={styles.centerBtn}
              onPress={() => this.setPlaying()}>
              <MaterialCommunityIconsIcon
                name="pause"
                style={styles.icon2}></MaterialCommunityIconsIcon>
            </TouchableOpacity>
          ) : (
            <TouchableOpacity
              style={styles.centerBtn}
              onPress={() => this.setPlaying()}>
              <MaterialCommunityIconsIcon
                name="play"
                style={styles.icon2}></MaterialCommunityIconsIcon>
            </TouchableOpacity>
          )}

          <TouchableOpacity style={styles.rightBtn} onPress={this.onNext}>
            <MaterialCommunityIconsIcon
              name="skip-next"
              style={styles.icon3}></MaterialCommunityIconsIcon>
          </TouchableOpacity>
        </View>
        <Text style={styles.songName}>{`${this.state.songName}`}</Text>
        {/* <Text style={styles.artistName}>Artist name</Text> */}
      </View>
    );
  }
}

// function MaterialCardWithRightButtons(props) {
//   const [playing, setPlaying] = React.useState(false);
//   const [currentIndex, setCurrentIndex] = React.useState(0);
//   const [image, setImage] = React.useState(
//     props.playlist['朋友組成電台'][0]['source']['imageSource'],
//   );
//   const [songName, setSongName] = React.useState(
//     props.playlist['朋友組成電台'][0]['name'],
//   );

//   onNext = () => {
//     if (currentIndex < props.playlist['朋友組成電台'].length) {
//       setCurrentIndex(currentIndex + 1);
//       setImage(
//         props.playlist['朋友組成電台'][currentIndex]['source']['imageSource'],
//       );
//       setSongName(props.playlist['朋友組成電台'][currentIndex]['name']);
//     }
//   };

//   onPrevious = () => {
//     if (currentIndex !== 0) {
//       setCurrentIndex(currentIndex - 1);
//       setImage(
//         props.playlist['朋友組成電台'][currentIndex]['source']['imageSource'],
//       );
//       setSongName(props.playlist['朋友組成電台'][currentIndex]['name']);
//     }
//   };

//   return (
//     <View style={[styles.container, props.style]}>
//       <Image source={{uri: image}} style={styles.cardItemImagePlace}></Image>
//       <View style={styles.buttonGroup}>
//         <TouchableOpacity style={styles.leftBtn} onPress={onPrevious}>
//           <MaterialCommunityIconsIcon
//             name="skip-previous"
//             style={styles.icon1}></MaterialCommunityIconsIcon>
//         </TouchableOpacity>
//         {playing ? (
//           <TouchableOpacity
//             style={styles.centerBtn}
//             onPress={() => setPlaying(false)}>
//             <MaterialCommunityIconsIcon
//               name="pause"
//               style={styles.icon2}></MaterialCommunityIconsIcon>
//           </TouchableOpacity>
//         ) : (
//           <TouchableOpacity
//             style={styles.centerBtn}
//             onPress={() => setPlaying(true)}>
//             <MaterialCommunityIconsIcon
//               name="play"
//               style={styles.icon2}></MaterialCommunityIconsIcon>
//           </TouchableOpacity>
//         )}

//         <TouchableOpacity style={styles.rightBtn} onPress={onNext}>
//           <MaterialCommunityIconsIcon
//             name="skip-next"
//             style={styles.icon3}></MaterialCommunityIconsIcon>
//         </TouchableOpacity>
//       </View>
//       <Text style={styles.songName}>{`${songName}`}</Text>
//       {/* <Text style={styles.artistName}>Artist name</Text> */}
//     </View>
//   );
// }

const styles = StyleSheet.create({
  container: {
    backgroundColor: '#FFF',
    flexWrap: 'nowrap',
    elevation: 3,
    borderRadius: 2,
    borderColor: '#CCC',
    borderWidth: 1,
    shadowOffset: {
      height: 2,
      width: -2,
    },
    shadowColor: '#000',
    shadowOpacity: 0.1,
    shadowRadius: 1.5,
    overflow: 'hidden',
  },
  cardItemImagePlace: {
    flex: 1,
    backgroundColor: '#ccc',
    minHeight: 210,
  },
  buttonGroup: {
    flexDirection: 'row',
    alignSelf: 'flex-end',
    padding: 8,
  },
  leftBtn: {
    marginRight: 8,
    marginLeft: 8,
    padding: 8,
  },
  icon1: {
    fontSize: 24,
    color: '#000',
    opacity: 0.5,
  },
  centerBtn: {
    marginRight: 8,
    marginLeft: 8,
    padding: 8,
  },
  icon2: {
    fontSize: 24,
    color: '#000',
    opacity: 0.5,
  },
  rightBtn: {
    marginRight: 8,
    marginLeft: 8,
    padding: 8,
  },
  icon3: {
    fontSize: 24,
    color: '#000',
    opacity: 0.5,
  },
  songName: {
    top: 210,
    left: 16,
    color: '#121212',
    position: 'absolute',
    fontFamily: 'roboto-regular',
  },
  artistName: {
    top: 244,
    left: 69,
    color: 'rgba(74,74,74,1)',
    position: 'absolute',
    opacity: 0.82,
    fontFamily: 'roboto-regular',
  },
});

// export default MaterialCardWithRightButtons;
<file_sep>import React from 'react';
import {
  ScrollView,
  AsyncStorage,
  ActivityIndicator,
  Dimensions,
  View,
} from 'react-native';
import {withStyles} from 'react-native-ui-kitten';
import {SafeAreaView} from 'react-navigation';
import {ChatList} from '../components/ChatList';
import {PARTNER_IMGS} from '../../../core/data/default';
import axios from 'axios';
import moment from 'moment';
import _ from 'lodash';

class ChatListDemoComponent extends React.Component {
  state = {
    // conversations: conversations,
    conversations: [],
    rawConversations: [],
    searchEnabled: false,
    msnoView: '',
  };

  componentDidMount() {
    AsyncStorage.getItem('user').then(res => {
      var user = JSON.parse(res);
      this.setState({msnoView: user['msno']});
      this.getChatList(user['msno']);
      this.props.navigation.addListener('willFocus', () =>
        this.getChatList(user['msno']),
      );
    });
  }

  handleOnNavigateBack = () => {
    AsyncStorage.getItem('user').then(res => {
      var user = JSON.parse(res);
      this.setState({msnoView: user['msno'], selfProfile: user});
      this.getChatList(user['msno']);
    });
  };

  getChatList = selfMsno => {
    axios
      .get('https://kkfriends.app/chat-list', {
        params: {
          msno_view: selfMsno,
        },
      })
      .then(res => {
        var data = res.data;
        var chats = data['chats'];
        this.setState({rawConversations: chats});
        var formatChats = _.map(chats, chat => {
          var date = moment(chat['ts'] * 1000);
          formatDate = date.format('HH:mm A');
          var user = this.formatProfile(chat['user_t']);
          var formatChat = {
            interlocutor: user,
            messages: [
              {
                author: user,
                date: formatDate,
                text: chat['message'],
                read: false,
                delivered: false,
              },
            ],
          };
          return formatChat;
        });
        this.setState({conversations: formatChats, isLoaded: true});
      });
  };

  formatProfile = profile => {
    var newProfile = {
      photo: {
        imageSource: _.has(PARTNER_IMGS, profile['msno'])
          ? PARTNER_IMGS[profile['msno']]
          : profile['img_url'],
      },
      about: '',
      firstName: profile['name'],
      lastName: '',
      gender: profile['gender'],
      age: 0,
      weight: 0,
      height: 0,
      job: '',
      inseam: 0,
      email: profile['email'],
      phoneNumber: '0',
      location: 'Taipei, Taiwan',
      friends: [],
      online: true,
      msno: profile['msno'],
    };
    return newProfile;
  };

  onConversationPress = index => {
    this.props.navigation.push('ChatChatScreen', {
      msnoFrom: this.state.msnoView,
      msnoTo: this.state.rawConversations[index]['msno_t'],
      onNavigateBack: this.handleOnNavigateBack,
      stack: 'Chat',
      selfProfile: this.state.selfProfile,
      otherProfile: this.state.conversations[index]['interlocutor'],
    });
  };

  render() {
    const {themedStyle} = this.props;
    if (this.state.isLoaded) {
      return (
        <SafeAreaView forceInset={{bottom: 'never'}}>
          <ScrollView>
            <ChatList
              searchEnabled={this.state.searchEnabled}
              conversations={this.state.conversations}
              onConversation={this.onConversationPress}
            />
          </ScrollView>
        </SafeAreaView>
      );
    } else {
      return (
        <View style={themedStyle.loadContainer}>
          <ActivityIndicator size={'large'} />
        </View>
      );
    }
  }
}

export const ChatListDemo = withStyles(ChatListDemoComponent, theme => ({
  loadContainer: {
    height: Dimensions.get('window').height,
    width: Dimensions.get('window').width,
    justifyContent: 'center',
  },
}));
<file_sep>import React from 'react';
import {Dimensions} from 'react-native';
import {withStyles} from 'react-native-ui-kitten';
import Carousel from 'react-native-snap-carousel';
import {CardListItem} from './CardListItem';

class CardListComponent extends React.Component {
  onItemPress = profile => {
    this.props.onItemPress(profile);
  };

  onItemLikePress = profile => {
    this.props.onItemLikePress(profile);
  };

  onItemCommentPress = profile => {
    this.props.onItemCommentPress(profile);
  };

  renderItem = (info, index) => {
    const {themedStyle} = this.props;

    return (
      <CardListItem
        style={themedStyle.item}
        profile={info.item}
        onPress={this.onItemPress}
        onLikePress={this.onItemLikePress}
        onCommentPress={this.onItemCommentPress}
      />
    );
  };

  render() {
    const {themedStyle, profiles} = this.props;
    return (
      <Carousel
        style={themedStyle.container}
        ref={c => {
          this._carousel = c;
        }}
        data={profiles}
        renderItem={this.renderItem}
        sliderWidth={Dimensions.get('window').width}
        itemWidth={Dimensions.get('window').width - 60}
      />
    );
  }
}

export const CardList = withStyles(CardListComponent, theme => ({
  container: {
    // paddingHorizontal: -16,
    // paddingVertical: 8,
    backgroundColor: theme['background-basic-color-2'],
  },
  item: {
    marginVertical: 8,
    backgroundColor: theme['background-basic-color-1'],
  },
}));
<file_sep>import React from 'react';
import {TouchableOpacity} from 'react-native';
import {withStyles, Text, Icon} from 'react-native-ui-kitten';

const HeartIconFill = style => <Icon name="heart" {...style} />;

const HeartIconOutline = style => <Icon name="heart-outline" {...style} />;

class LikeButtonComponent extends React.Component {
  render() {
    const {
      style,
      themedStyle,
      textStyle,
      children,
      filled,
      ...restProps
    } = this.props;

    return (
      <TouchableOpacity style={[themedStyle.container, style]} {...restProps}>
        {filled
          ? HeartIconFill(themedStyle.icon)
          : HeartIconOutline(themedStyle.icon)}
        <Text style={[themedStyle.valueLabel, textStyle]} category="p2">
          {children}
        </Text>
      </TouchableOpacity>
    );
  }
}

export const LikeButton = withStyles(LikeButtonComponent, theme => ({
  container: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  icon: {
    width: 36,
    height: 36,
    tintColor: theme['color-danger-default'],
  },
  valueLabel: {
    marginHorizontal: 8,
  },
}));
<file_sep>import React from 'react';
import {withStyles, Text} from 'react-native-ui-kitten';
import {textStyle} from '../common/style';

class MessageContentComponent extends React.Component {
  render() {
    const {themedStyle, message, children} = this.props;

    if (message.text) {
      return <Text style={themedStyle.messageLabel}>{message.text}</Text>;
    } else if (children) {
      return children;
    } else {
      return null;
    }
  }
}

export const MessageContent = withStyles(MessageContentComponent, theme => ({
  messageLabel: {
    color: 'white',
    ...textStyle.paragraph,
  },
}));
<file_sep>import React from 'react';
import {Platform, View} from 'react-native';
import {Button, Input, List, withStyles, Icon} from 'react-native-ui-kitten';
import {ChatMessage} from '../../messages/ChatMessage';
import {profile1, profile2} from '../../../core/data/profile';
import {AvoidKeyboard} from '../../common/avoidKeyboard';
import {textStyle} from '../../common/style';
import {StringValidator} from '../../../core/validators';

const MicIconFill = style => <Icon name="mic" {...style} />;

const PaperPlaneIconFill = style => <Icon name="paper-plane" {...style} />;

const PlusIconFill = style => <Icon name="plus" {...style} />;

class ChatComponent extends React.Component {
  listRef = React.createRef();

  onListContentSizeChange = () => {
    setTimeout(() => this.listRef.current.scrollToEnd({animated: true}), 0);
  };

  onNewMessageChange = text => {
    this.props.onNewMessageChange(text);
  };

  onMessageAdd = () => {
    this.props.onMessageAdd();
  };

  shouldRenderSendButton = () => {
    const {newMessage} = this.props;

    return StringValidator(newMessage);
  };

  createUiMessages = () => {
    const {conversation} = this.props;

    return conversation.messages.map(message => {
      if (message.author === this.props.otherProfile) {
        return {
          ...message,
          alignment: 'row-left',
        };
      } else if (message.author === this.props.selfProfile) {
        return {
          ...message,
          alignment: 'row-right',
        };
      }
    });
  };

  renderMessage = info => {
    const {themedStyle} = this.props;

    return (
      <ChatMessage
        style={themedStyle.message}
        index={info.index}
        message={info.item}
        alignment={info.item.alignment}
      />
    );
  };

  renderSendMessageButton = () => {
    const {themedStyle} = this.props;

    return (
      <Button
        style={themedStyle.addMessageButton}
        appearance="ghost"
        size="large"
        icon={PaperPlaneIconFill}
        onPress={this.onMessageAdd}
      />
    );
  };

  keyboardOffset = height => {
    return Platform.select({
      ios: height,
      android: 0,
    });
  };

  render() {
    const {themedStyle, newMessage} = this.props;

    const sendMessageButtonElement = this.shouldRenderSendButton()
      ? this.renderSendMessageButton()
      : null;

    return (
      <AvoidKeyboard
        style={themedStyle.container}
        autoDismiss={false}
        offset={this.keyboardOffset}>
        <List
          ref={this.listRef}
          contentContainerStyle={themedStyle.chatContainer}
          data={this.createUiMessages()}
          onContentSizeChange={this.onListContentSizeChange}
          renderItem={this.renderMessage}
        />
        <View style={themedStyle.inputContainer}>
          <Button
            style={themedStyle.addMessageButton}
            textStyle={textStyle.button}
            icon={PlusIconFill}
            onPress={() => {}}
          />
          <Input
            icon={MicIconFill}
            style={themedStyle.messageInput}
            textStyle={textStyle.paragraph}
            value={newMessage}
            placeholder="Message..."
            onChangeText={this.onNewMessageChange}
          />
          {sendMessageButtonElement}
        </View>
      </AvoidKeyboard>
    );
  }
}

export const Chat = withStyles(ChatComponent, theme => ({
  container: {
    flex: 1,
    backgroundColor: theme['background-basic-color-2'],
  },
  chatContainer: {
    paddingHorizontal: 16,
    paddingVertical: 12,
  },
  message: {
    marginVertical: 12,
  },
  inputContainer: {
    padding: 16,
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    backgroundColor: theme['background-basic-color-1'],
  },
  addMessageButton: {
    width: 26,
    height: 26,
    borderRadius: 26,
  },
  messageInput: {
    flex: 1,
    marginHorizontal: 8,
  },
}));
<file_sep>import React from 'react';
import {View} from 'react-native';
import {withStyles} from 'react-native-ui-kitten';

class ActivityBarComponent extends React.Component {
  render() {
    const {style, themedStyle, children, ...restProps} = this.props;

    return (
      <View style={[themedStyle.container, style]} {...restProps}>
        {children}
      </View>
    );
  }
}

export const ActivityBar = withStyles(ActivityBarComponent, theme => ({
  container: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
  },
}));
