react-native#LayoutAnimation JavaScript Examples

The following examples show how to use react-native#LayoutAnimation. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: ClusteredMapView.js    From guardioes-app with Apache License 2.0 6 votes vote down vote up
ClusteredMapView.defaultProps = {
  minZoom: 1,
  maxZoom: 16,
  extent: 512,
  accessor: 'location',
  animateClusters: true,
  clusteringEnabled: true,
  clusterPressMaxChildren: 100,
  preserveClusterPressBehavior: true,
  width: Dimensions.get('window').width,
  height: Dimensions.get('window').height,
  layoutAnimationConf: LayoutAnimation.Presets.spring,
  edgePadding: { top: 10, left: 10, right: 10, bottom: 10 }
}
Example #2
Source File: ui.js    From react-native-loop-game with MIT License 6 votes vote down vote up
initLayout = (duration = 200, type = 'linear') => {
  if (type === 'spring') {
    return LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);
  }

  return LayoutAnimation.configureNext({
    duration,
    create: {
      duration,
      type: LayoutAnimation.Types[type],
      property: LayoutAnimation.Properties.opacity,
    },
    update: {
      duration,
      type: LayoutAnimation.Types[type],
      property: LayoutAnimation.Properties.opacity,
    },
    delete: {
      duration,
      type: LayoutAnimation.Types[type],
      property: LayoutAnimation.Properties.opacity,
    },
  });
}
Example #3
Source File: BirthdayDataContext.js    From Reminder-App with MIT License 5 votes vote down vote up
Birthday_reducer = (state, action) => {
  switch (action.type) {
    case "add_birthday":
      LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);
      let data = [
        ...state,
        {
          text: `Tap to change the name`,
          key: `key-${1 + Math.random() * 99}`,
          height: 75,
          Date: action.payload.time,
          notificationId: action.payload.value,
        },
      ];
      storeData(data);
      return data;
    case "init_data":
      if (action.payload === null) {
        return [];
      } else return action.payload;
    case "delete_reminder":
    case "delete_birthday":
      LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
      data = state.filter((d) => d !== action.payload);
      storeData(data);
      return data;
    case "edit":
      data = state.filter((d) => {
        if (d == action.payload.selecteditem) {
          let tep = action.payload.selecteditem;
          tep.Date = action.payload.time;
          tep.text = action.payload.text;
          tep.notificationId = action.payload.id;
          return tep;
        } else return d;
      });
      storeData(data);
      return data;
    default:
      return state;
  }
}
Example #4
Source File: ReminderDataContext.js    From Reminder-App with MIT License 5 votes vote down vote up
Reminder_reducer = (state, action) => {
  switch (action.type) {
    case "add_reminder":
      LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);
      let data = [
        ...state,
        {
          text: `Tap to edit`,
          key: `key-${1 + Math.random() * 99}`,
          height: 75,
          Date: action.payload.time,
          notificationId: action.payload.value,
        },
      ];
      storeData(data);
      return data;
    case "init_data":
      if (action.payload === null) {
        return [];
      } else return action.payload;
    case "delete_reminder":
      LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
      data = state.filter((d) => d !== action.payload);
      storeData(data);
      return data;
    case "snooze":
      data = state.filter((d) => {
        if (d.notificationId == action.payload.id) {
          let tep = d;
          tep.Date = action.payload.time;
          tep.notificationId = action.payload.newid;
          return tep;
        } else return d;
      });
      storeData(data);
      return data;
    case "edit":
      data = state.filter((d) => {
        if (d == action.payload.selecteditem) {
          let tep = action.payload.selecteditem;
          tep.Date = action.payload.time;
          tep.text = action.payload.text;
          tep.notificationId = action.payload.id;
          return tep;
        } else return d;
      });
      storeData(data);
      return data;
    default:
      return state;
  }
}
Example #5
Source File: ClusteredMapView.js    From guardioes-app with Apache License 2.0 5 votes vote down vote up
componentWillUpdate(nextProps, nextState) {
    if (!this.isAndroid && this.props.animateClusters && this.clustersChanged(nextState))
      LayoutAnimation.configureNext(this.props.layoutAnimationConf)
  }
Example #6
Source File: OnBoarding.js    From reactnative-best-practice with MIT License 5 votes vote down vote up
export default function OnBoardingScreen() {
  const navigation = useNavigation();
  const {navigate} = navigation;

  const skipContext = useContext(CTX);
  const {_seen} = skipContext;

  useEffect(() => {
    LayoutAnimation.easeInEaseOut();
  });

  function _renderItem({item}) {
    return (
      <View style={[styles.slide, {backgroundColor: item.backgroundColor}]}>
        <Text style={item.color}>{item.title}</Text>
        <Image style={styles.image} source={item.image} />
        <Text style={styles.text}>{item.text}</Text>
      </View>
    );
  }
  function _onDone() {
    // User finished the introduction. Show real app through
    // navigation or simply by controlling state
    // this.setState({showRealApp: true});
    _seen();
  }
  _renderNextButton = () => {
    return (
      <View style={styles.buttonCircle}>
        <FontAwesome5
          name="chevron-right"
          color="#FFFFFF"
          size={24}
          style={{backgroundColor: 'transparent'}}
        />
      </View>
    );
  };
  _renderDoneButton = () => {
    return (
      <View style={styles.buttonCircle}>
        <FontAwesome5
          name="check-circle"
          color="#FFFFFF"
          size={24}
          style={{backgroundColor: 'transparent'}}
        />
      </View>
    );
  };
  return (
    <AppIntroSlider
      renderItem={_renderItem}
      slides={slides}
      onDone={_onDone}
      activeDotStyle={{backgroundColor: primaryColor}}
      renderNextButton={_renderNextButton}
      renderDoneButton={_renderDoneButton}
    />
  );
}
Example #7
Source File: ReadMore.js    From react-native-read-more with MIT License 5 votes vote down vote up
readmoreAnimation = LayoutAnimation.create(
  300,
  LayoutAnimation.Types.easeOut,
  LayoutAnimation.Properties.opacity,
)
Example #8
Source File: Birthday_Screen.js    From Reminder-App with MIT License 4 votes vote down vote up
function My_List() {
  const { state, add_birthday, delete_birthday, edit } = useContext(Context);
  const { colors } = useTheme();
  const [showmodel, setmodel] = useState(false);
  const [selecteditem, setselecteditem] = useState(null);

  useEffect(() => {
    state.sort(function (a, b) {
      var keyA = new Date(a.Date).getTime(),
        keyB = new Date(b.Date).getTime();
      if (keyA < keyB) return -1;
      if (keyA > keyB) return 1;
      return 0;
    });
  }, [state]);

  useEffect(() => {
    state.map((item) => {
      edit({ selecteditem: item, text: item.text, time: item.Date });
    });
  }, []);

  let itemRefs = new Map();

  const chnage_model = (item) => {
    LayoutAnimation.configureNext(
      LayoutAnimation.create(
        200,
        LayoutAnimation.Types.linear,
        LayoutAnimation.Properties.opacity
      )
    );
    setselecteditem(item);
    setmodel(!showmodel);
  };
  const hide_model = () => {
    LayoutAnimation.configureNext(
      LayoutAnimation.create(
        200,
        LayoutAnimation.Types.linear,
        LayoutAnimation.Properties.opacity
      )
    );
    setmodel(false);
    setselecteditem(null);
  };

  function emptylist() {
    return (
      <View
        style={{
          justifyContent: "center",
          alignItems: "center",
        }}
      >
        <Text
          style={[
            styles.text,
            { fontSize: 25, textAlign: "center", color: colors.text },
          ]}
        >
          {"Click on the plus icon to add Birthday Reminder."}
        </Text>
      </View>
    );
  }

  function footer() {
    return (
      <View
        style={{
          height: 75,
          justifyContent: "center",
          alignItems: "center",
        }}
      >
        <TouchableOpacity
          onPress={() => {
            add_birthday();
          }}
        >
          <AntDesign name="plus" size={34} color={colors.text} />
        </TouchableOpacity>
      </View>
    );
  }
  if (showmodel) {
    return (
      <Model edit={edit} hide_model={hide_model} selecteditem={selecteditem} />
    );
  }
  function header() {
    return (
      <View style={styles.TitleContainer}>
        <Text style={[styles.text, { fontSize: 45, color: colors.text }]}>
          Birthdays
        </Text>
      </View>
    );
  }
  return (
    <View style={styles.container}>
      <FlatList
        ListHeaderComponent={header}
        ListEmptyComponent={emptylist}
        style={{ flex: 0.8 }}
        keyExtractor={(item) => item.key}
        data={state}
        renderItem={({ item, index }) => (
          <Element
            index={index}
            item={item}
            itemRefs={itemRefs}
            deleteItem={(item) => {
              delete_birthday(item);
            }}
            showmodel={chnage_model}
          />
        )}
        ListFooterComponent={footer}
      />
    </View>
  );
}
Example #9
Source File: Reminder_Screen.js    From Reminder-App with MIT License 4 votes vote down vote up
function My_List() {
  const { state, add_reminder, delete_reminder, edit } = useContext(Context);

  const { colors } = useTheme();
  const [showmodel, setmodel] = useState(false);
  const [selecteditem, setselecteditem] = useState(null);

  let itemRefs = new Map();

  useEffect(() => {
    state.map((item) => {
      let ti = new Date(item.Date);
      if (ti.getTime() <= Date.now()) {
        delete_reminder(item);
      }
    });
    state.sort(function (a, b) {
      var keyA = new Date(a.Date).getTime(),
        keyB = new Date(b.Date).getTime();
      if (keyA < keyB) return -1;
      if (keyA > keyB) return 1;
      return 0;
    });
  }, [state]);

  const chnage_model = (item) => {
    LayoutAnimation.configureNext(
      LayoutAnimation.create(
        200,
        LayoutAnimation.Types.linear,
        LayoutAnimation.Properties.opacity
      )
    );
    setselecteditem(item);
    setmodel(!showmodel);
  };
  const hide_model = () => {
    LayoutAnimation.configureNext(
      LayoutAnimation.create(
        200,
        LayoutAnimation.Types.linear,
        LayoutAnimation.Properties.opacity
      )
    );
    setmodel(false);
    setselecteditem(null);
  };

  function emptylist() {
    return (
      <View
        style={{
          justifyContent: "center",
          alignItems: "center",
        }}
      >
        <Text
          style={[
            styles.text,
            { fontSize: 25, textAlign: "center", color: colors.text },
          ]}
        >
          {
            "Looks like you have no reminder! \n Click on the plus icon to add one."
          }
        </Text>
      </View>
    );
  }

  function footer() {
    return (
      <View
        style={{
          height: 75,
          justifyContent: "center",
          alignItems: "center",
        }}
      >
        <TouchableOpacity
          onPress={() => {
            add_reminder();
          }}
        >
          <AntDesign name="plus" size={34} color={colors.text} />
        </TouchableOpacity>
      </View>
    );
  }
  if (showmodel) {
    return (
      <Model edit={edit} hide_model={hide_model} selecteditem={selecteditem} />
    );
  }
  function header() {
    return (
      <View style={styles.TitleContainer}>
        <Text style={[styles.text, { fontSize: 45, color: colors.text }]}>
          Reminders
        </Text>
      </View>
    );
  }
  return (
    <View style={styles.container}>
      <FlatList
        ListHeaderComponent={header}
        ListEmptyComponent={emptylist}
        style={{ flex: 0.8 }}
        keyExtractor={(item) => item.key}
        data={state}
        renderItem={({ item, index }) => (
          <Element
            index={index}
            item={item}
            itemRefs={itemRefs}
            deleteItem={(item) => {
              delete_reminder(item);
            }}
            showmodel={chnage_model}
          />
        )}
        ListFooterComponent={footer}
        // onDragEnd={({ data }) => this.setState({ data })}
        // activationDistance={10}
      />
    </View>
  );
}
Example #10
Source File: LoginScreen.js    From geometry_3d with MIT License 4 votes vote down vote up
function LoginScreen(props) {
  const { navigate } = useNavigation();
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [errorMessage, setErrorMessage] = useState("");
  const [visible, setVisible] = useState(false);
  const handleLogin = () => {
    setVisible(() => true);
    fb.auth
      .signInWithEmailAndPassword(email, password)
      .then(() => {
        props.reduxSetCurrentUser({
          email: email,
          password: password,
        });
        setVisible(() => false);
        //console.log(props.currentUser);
      })
      .catch((error) => {
        setErrorMessage(error.message);
        setVisible(() => false);
      });
  };
  useEffect(() => {
    LayoutAnimation.easeInEaseOut();
  });
  return visible ? (
    <LoadingScreen />
  ) : (
    <KeyboardAwareScrollView
      resetScrollToCoords={{ x: 0, y: 0 }}
      contentContainerStyle={styles.container}
      enableOnAndroid={true}
      keyboardShouldPersistTaps="handled"
      scrollEnabled={true}
      enableAutomaticScroll={Platform.OS === "ios"}
    >
      <StatusBar barStyle="light-content"></StatusBar>
      <ScrollView keyboardShouldPersistTaps={'handled'} style={{backgroundColor: 'black'}}>
        <Text style={styles.greeting}>{"Hello! \nWelcome back"}</Text>
        <View style={styles.errorMessage}>
          <Text style={styles.error}>{errorMessage}</Text>
        </View>
        <View style={styles.form}>
          <View>
            <Text style={styles.inputTitle}>Email Address</Text>
            <TextInput
              style={styles.input}
              autoCapitalize="none"
              onChangeText={(emailInput) => setEmail(() => emailInput.trim())}
              value={email}
            ></TextInput>
          </View>
          <View>
            <Text textBreakStrategy={"simple"} style={styles.inputTitle}>Password</Text>
            <TextInput
              style={styles.input}
              secureTextEntry
              autoCapitalize="none"
              onChangeText={(passwordInput) => setPassword(() => passwordInput.trim())}
              value={password}
            ></TextInput>
          </View>
          <TouchableOpacity style={styles.button} onPress={handleLogin}>
            <Text textBreakStrategy={"simple"} style={{ color: "white", fontWeight: "500" }}>Sign in</Text>
          </TouchableOpacity>
          <TouchableOpacity style={{...styles.button, marginTop: 10, backgroundColor: "#2bffea"}} onPress={() => {
            navigate("App", {}, NavigationActions.navigate({routeName: "HomeScreen"}))
          }}>
            <Text textBreakStrategy={"simple"} style={{ color: "black", fontWeight: "500" }}>Guest session</Text>
          </TouchableOpacity>
          <TouchableOpacity
            style={{ alignSelf: "center", marginTop: 32 }}
            onPress={() => navigate("Register")}
          >
            <Text textBreakStrategy={"simple"} style={{ color: "white", fontSize: 13 }}>
              First time?
              <Text textBreakStrategy={"simple"} style={{ color: "#478eff", fontWeight: "500" }}>
                {" "}
                Sign up!
              </Text>
            </Text>
          </TouchableOpacity>
        </View>
      </ScrollView>
    </KeyboardAwareScrollView>
  );
}
Example #11
Source File: RegisterScreen.js    From geometry_3d with MIT License 4 votes vote down vote up
export default function RegisterScreen() {
  const navigate = useNavigation();
  const [name, setName] = useState("");
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [errorMessage, setErrorMessage] = useState("");
  const [visible, setVisible] = useState(false);

  const handleRegister = () => {
    if (errorMessage === "") {
      setVisible(() => true);
      fb.auth
        .createUserWithEmailAndPassword(email, password)
        .then((userCredentials) => {
          setVisible(() => false);
          fb.userCollection.doc(userCredentials.user.uid).set({
            scenes: [],
            uid: userCredentials.user.uid
          });
          return userCredentials.user.updateProfile({
            displayName: name,
          });
        })
        .catch((error) => {
          setVisible(() => false);
          setErrorMessage(error);
        });
    }
  };
  useEffect(() => {
    LayoutAnimation.easeInEaseOut();
  });
  return visible ? (
    <LoadingScreen />
  ) : (
    <KeyboardAwareScrollView
      resetScrollToCoords={{ x: 0, y: 0 }}
      contentContainerStyle={styles.container}
      enableOnAndroid={true}
      keyboardShouldPersistTaps="handled"
      scrollEnabled={true}
      enableAutomaticScroll={Platform.OS === "ios"}
    >
      <StatusBar barStyle="light-content"></StatusBar>
      <ScrollView
          keyboardShouldPersistTaps={"handled"}
        style={{
          height: "100%",
          backgroundColor: 'black'
        }}
      >
        <TouchableOpacity style={styles.back} onPress={() => navigate.goBack()}>
          <Ionicons name="ios-arrow-round-back" color="white" size={32} />
        </TouchableOpacity>
        <Text style={styles.greeting}>{"Become one of us"}</Text>
        <View style={styles.errorMessage}>
          <Text style={styles.error}>{errorMessage.message}</Text>
        </View>
        <View style={styles.form}>
          <View>
            <Text style={styles.inputTitle}>Name</Text>
            <TextInput
              style={styles.input}
              autoCapitalize="none"
              onChangeText={(nameInput) => setName(() => nameInput.trim())}
              value={name}
            ></TextInput>
          </View>
          <View>
            <Text style={styles.inputTitle}>Email Address</Text>
            <TextInput
              style={styles.input}
              autoCapitalize="none"
              onChangeText={(emailInput) => setEmail(() => emailInput.trim())}
              value={email}
            ></TextInput>
          </View>
          <View>
            <Text style={styles.inputTitle}>Password</Text>
            <TextInput
              style={styles.input}
              secureTextEntry
              autoCapitalize="none"
              onChangeText={(password) => setPassword(() => password.trim())}
              value={password}
            ></TextInput>
          </View>
          <View>
            <Text style={styles.inputTitle}>Confirm Password</Text>
            <TextInput
              style={styles.input}
              secureTextEntry
              autoCapitalize="none"
              onChangeText={(passwordInput) => {
                //setPasswordConfirm(passwordInput)
                if (passwordInput != password)
                  setErrorMessage(() => "Incorrect Passwords");
                else setErrorMessage(() => "");
              }}
            ></TextInput>
          </View>
          <TouchableOpacity style={styles.button} onPress={handleRegister}>
            <Text style={{ color: "white", fontWeight: "500" }}>Register</Text>
          </TouchableOpacity>
        </View>
      </ScrollView>
    </KeyboardAwareScrollView>
  );
}
Example #12
Source File: ReadMore.js    From react-native-read-more with MIT License 4 votes vote down vote up
ReadMore = ({
  numberOfLines,
  style,
  wrapperStyle,
  children,
  seeMoreStyle,
  seeMoreText,
  seeLessStyle,
  seeLessText,
  animate,
  customTextComponent: TextComponent,
  ellipsis,
  allowFontScaling,
  onExpand,
  onCollapse,
  expandOnly,
  seeMoreOverlapCount,
  debounceSeeMoreCalc,
  onReady,
  seeMoreContainerStyleSecondary,
  onSeeMoreBlocked,
  debug,
  ...restProps
}) => {
  const [additionalProps, setAdditionalProps] = useState({});
  // hiddenTextLinesWithSeeLess comes from hidden component two
  const [hiddenTextLinesWithSeeLess, setHiddenTextLinesWithSeeLess] = useState(
    [],
  );
  const [textWidth, setTextWidth] = useState(0);
  const [truncatedLineOfImpact, setTruncatedLineOfImpact] = useState('');
  const [truncatedLineOfImpactWidth, setTruncatedLineOfImpactWidth] =
    useState(0);
  const [lines, setLines] = useState([]);
  const [collapsedLines, setCollapsedLines] = useState([]);
  const [seeMoreRightPadding, setSeeMoreRightPadding] = useState(0);
  // mount or unmount hidden components
  const [mountHiddenTextOne, setMountHiddenTextOne] = useState(false);
  const [mountHiddenTextTwo, setMountHiddenTextTwo] = useState(false);
  const [mountHiddenTextThree, setMountHiddenTextThree] = useState(false);
  const [mountHiddenTextFour, setMountHiddenTextFour] = useState(false);
  const [mountHiddenTextFive, setMountHiddenTextFive] = useState(false);
  const [mountHiddenTextSix, setMountHiddenTextSix] = useState(false);
  // initial measurement is in progress
  const [isMeasured, setIsMeasured] = useState(false);
  const [isReady, setIsReady] = useState(false);
  // logic decisioning params
  const [seeMore, setSeeMore] = useState(false);
  const [collapsed, setCollapsed] = useState(true);
  const [afterCollapsed, setAfterCollapsed] = useState(true);
  // copy of children with only text
  const [collapsedChildren, setCollapsedChildren] = useState(null);
  const [reconciledLineOfImpact, setReconciledLineOfImpact] = useState('');
  // eslint-disable-next-line prettier/prettier
  const [reconciledLineOfImpactWidth, setReconciledLineOfImpactWidth] = useState(0);
  // width of see more component
  const [seeMoreWidth, setSeeMoreWidth] = useState(0);
  const [hideEllipsis, setHideEllipsis] = useState(false);

  // eslint-disable-next-line react-hooks/exhaustive-deps
  const log = useCallback(logClosure(debug), [debug]);

  const onSeeMoreViewLayout = useCallback(
    ({
      nativeEvent: {
        layout: {width},
      },
    }) => {
      setSeeMoreWidth(width);
    },
    [setSeeMoreWidth],
  );

  const onTextLayoutOne = useCallback(
    ({nativeEvent: {lines: _lines}}) => {
      setLines(_lines);
      setMountHiddenTextOne(false);
      setMountHiddenTextTwo(true);
    },
    [setLines, setMountHiddenTextOne],
  );

  const onTextLayoutTwo = useCallback(
    ({nativeEvent: {lines: _lines}}) => {
      setHiddenTextLinesWithSeeLess(_lines);
      setMountHiddenTextTwo(false);
      setMountHiddenTextThree(true);
    },
    [
      setHiddenTextLinesWithSeeLess,
      setMountHiddenTextTwo,
      setMountHiddenTextThree,
    ],
  );

  const onLayoutHiddenTextThree = useCallback(
    event => {
      const _event = event; // clone event
      const _width = _event?.nativeEvent?.layout?.width || 0;
      setTextWidth(_width);
      setMountHiddenTextThree(false);
    },
    [setTextWidth, setMountHiddenTextThree],
  );

  const onTextLayoutHiddenTextThree = useCallback(
    event => {
      const _event = event; // clone event
      if (collapsed) {
        const _lines = _event?.nativeEvent?.lines || [];
        setCollapsedLines(_lines);
      }
    },
    [setCollapsedLines, collapsed],
  );

  const onLayoutFour = useCallback(
    ({
      nativeEvent: {
        layout: {width},
      },
    }) => {
      setTruncatedLineOfImpactWidth(width);
      setMountHiddenTextFour(false);
      setMountHiddenTextFive(true);
    },
    [
      setTruncatedLineOfImpactWidth,
      setMountHiddenTextFour,
      setMountHiddenTextFive,
    ],
  );

  const onLayoutHiddenTextFive = useCallback(() => {
    setMountHiddenTextFive(false);
    setMountHiddenTextSix(true);
  }, [setMountHiddenTextFive, setMountHiddenTextSix]);

  const onTextLayoutHiddenTextFive = useCallback(
    ({nativeEvent: {lines: _lines}}) => {
      const _lineOfImpact = _lines[numberOfLines - 1];
      setReconciledLineOfImpact(_lineOfImpact?.text?.trimEnd?.() || '');
    },
    [numberOfLines, setReconciledLineOfImpact],
  );

  const onLayoutHiddenTextSix = useCallback(
    ({
      nativeEvent: {
        layout: {width},
      },
    }) => {
      setMountHiddenTextSix(false);
      setReconciledLineOfImpactWidth(reconciledLineOfImpact ? width : 0);
    },
    [
      setReconciledLineOfImpactWidth,
      setMountHiddenTextSix,
      reconciledLineOfImpact,
    ],
  );

  const toggle = useCallback(() => {
    if (onSeeMoreBlocked) {
      onSeeMoreBlocked();
    } else {
      setCollapsed(prev => !prev);
    }
  }, [setCollapsed, onSeeMoreBlocked]);

  const updateLineOfImpact = useCallback(
    (_text = '', resetCollapsedChildren = true) => {
      setHideEllipsis(!_text?.length);
      setTruncatedLineOfImpact(_text || '');

      if (!_text?.length) {
        // reset width if no text
        // otherwise an effect will update the width
        setTruncatedLineOfImpactWidth(0);
        setReconciledLineOfImpactWidth(0);
        setSeeMoreRightPadding(0);
        setIsMeasured(true);
      }

      if (resetCollapsedChildren) {
        setCollapsedChildren(null);
      }
    },
    [
      setHideEllipsis,
      setTruncatedLineOfImpact,
      setTruncatedLineOfImpactWidth,
      setCollapsedChildren,
      setIsMeasured,
    ],
  );

  const measureSeeMoreLine = useCallback(() => {
    if (
      numberOfLines < 1 ||
      !lines.length ||
      !collapsedLines.length ||
      !seeMore ||
      !seeMoreWidth
    ) {
      log('terminating measurements for see more - 1');
      return;
    }

    if (!lines[numberOfLines - 1] || !collapsedLines[numberOfLines - 1]) {
      log('terminating measurements for see more - 2');
      return;
    }

    // find line of impact
    let _lineOfImpact = lines[numberOfLines - 1];
    _lineOfImpact.index = numberOfLines - 1;
    if (Platform.OS === 'ios') {
      const modifiedIndex = lines.findIndex((_line, index) => {
        if (index < numberOfLines - 1 || !_line.text?.trimEnd?.()) {
          return false;
        }
        return collapsedLines[numberOfLines - 1].text.includes(_line.text);
      });
      if (modifiedIndex !== -1) {
        _lineOfImpact = lines[modifiedIndex];
        _lineOfImpact.index = modifiedIndex;
      }
    }

    const _trimmedText = _lineOfImpact?.text?.trimEnd?.();

    // calculate how many characters to cut off if any
    // trim right before -> spaces and \n
    // width from line, textWidth, seeMoreWidth

    if (_trimmedText?.length && !textWidth) {
      // textWidth is being measured
      return;
    }

    // case 1
    log('case 1');
    // if no text after right trim
    // hide ellipsis
    // move see more to beginning
    if (!_trimmedText?.length) {
      return updateLineOfImpact(_trimmedText);
    }

    const availableWidth = textWidth - seeMoreWidth;

    // case 2
    log('case 2');
    // text is there but no need to put \n
    // enough space for see more text on right side
    if (_lineOfImpact.width < availableWidth) {
      return updateLineOfImpact(_trimmedText);
    }

    const seeMoreTextLength =
      `${ellipsis} ${seeMoreText}`.length + seeMoreOverlapCount;

    // case 3
    log('case 3');
    // many spaces at the end of text
    // so still no need to cutoff the text at end with \n
    const spaceDifference = _lineOfImpact?.text?.length - _trimmedText?.length;
    if (spaceDifference >= seeMoreTextLength) {
      return updateLineOfImpact(_trimmedText);
    }

    // case 4
    log('case 4');
    // create collapsed children with \n at the point
    const linesTillImpact = Array(_lineOfImpact.index + 1)
      .fill({})
      .map((_e, index) => lines[index]);
    const charactersBeforeSeeMore = linesToCharacters(linesTillImpact);
    const charactersLengthTillSeeMore =
      charactersBeforeSeeMore?.trimEnd?.()?.length || 0;
    // text break position for collapsed text
    const textBreakPosition = charactersLengthTillSeeMore - seeMoreTextLength;

    const _truncatedText =
      _trimmedText
        ?.substr(0, _trimmedText.length - seeMoreTextLength)
        ?.trimEnd?.() || '';

    // go to this position and insert \n
    let charactersToTraverse = textBreakPosition;
    let nodeFound = false;
    const modifiedChildrenObjects = getTextByChildren(children, TextComponent)
      ?.map(_childObject => {
        if (nodeFound) {
          return _childObject;
        }
        if (_childObject.content.length > charactersToTraverse) {
          // this node is the one
          nodeFound = true;
          const childContent = insertAt(
            _childObject.content,
            '\n',
            charactersToTraverse,
          );
          return {
            type: _childObject?.type,
            content: childContent,
            child:
              _childObject?.type === 'string'
                ? childContent
                : React.cloneElement(
                    _childObject,
                    _childObject.props,
                    childContent,
                  ),
          };
        }
        charactersToTraverse =
          charactersToTraverse - _childObject.content.length;

        return _childObject;
      })
      ?.map(_updatedObjects => {
        return _updatedObjects.child;
      });

    if (nodeFound) {
      setCollapsedChildren(modifiedChildrenObjects);
      return updateLineOfImpact(_truncatedText, false);
    }

    // todo: inform user
    // error case
    return updateLineOfImpact(_trimmedText);
  }, [
    numberOfLines,
    lines,
    collapsedLines,
    seeMore,
    textWidth,
    seeMoreWidth,
    ellipsis,
    seeMoreText,
    seeMoreOverlapCount,
    children,
    TextComponent,
    updateLineOfImpact,
    log,
  ]);

  const textProps = afterCollapsed
    ? {
        numberOfLines,
        ellipsizeMode: 'clip',
      }
    : {};

  const commonHiddenComponentProps = {
    ...additionalProps,
    style: StyleSheet.flatten([
      Array.isArray(style) ? StyleSheet.flatten(style) : style,
      styles.hiddenTextAbsolute,
    ]),
  };

  const hiddenComponentPropsLineOfImpact = {
    ...additionalProps,
    style: StyleSheet.flatten([
      Array.isArray(style) ? StyleSheet.flatten(style) : style,
      styles.hiddenTextAbsoluteCompact,
    ]),
  };

  // use after measured here
  const seeMoreTextHidingStyle = !isMeasured
    ? styles.transparentColor
    : styles.transparentBackground;
  const seeMoreContainerStyle = [
    hideEllipsis
      ? styles.seeMoreContainerEllpisisHidden
      : styles.seeMoreContainer,
    {
      marginRight: seeMoreRightPadding,
    },
  ];

  useEffect(() => {
    const _seeMore = lines.length > numberOfLines;
    setSeeMore(_seeMore);

    if (!lines?.length) {
      return;
    }

    if (!_seeMore) {
      log('no measurement is needed');
      onReady();
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [numberOfLines, lines]);

  useEffect(() => {
    if (collapsed === afterCollapsed) {
      return;
    }

    const callback = collapsed ? onCollapse : onExpand;
    if (animate) {
      LayoutAnimation.configureNext(readmoreAnimation, callback);
    } else {
      callback();
    }
    setAfterCollapsed(collapsed);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [collapsed]);

  useEffect(() => {
    const handle = setTimeout(() => {
      // to commence measurement chain
      // we should mount component 1
      // also reset isMeasured
      setMountHiddenTextOne(true);
    }, debounceSeeMoreCalc);
    return () => clearTimeout(handle);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [
    // re calc if any of these params change
    numberOfLines,
    style,
    wrapperStyle,
    children,
    seeMoreStyle,
    seeMoreText,
    seeLessStyle,
    seeLessText,
    ellipsis,
    additionalProps,
  ]);

  useEffect(() => {
    // a map of additional props to be passed down
    // in hidden text components other than style
    // for accurate measurements
    const _additionalProps = {};

    // pick selected params
    if (allowFontScaling !== undefined) {
      _additionalProps.allowFontScaling = allowFontScaling;
    }

    setAdditionalProps(_additionalProps);
  }, [allowFontScaling]);

  useEffect(() => {
    if (mountHiddenTextTwo && !seeMoreWidth && collapsedLines?.length) {
      return;
    }
    // only start measurement after component 2 is unmounted and see more width is calculated
    // since component 1 mounts -> unmounts -> mounts component 2
    // then component 2 unmounts itself
    // and then all measurement params are available
    const handle = setTimeout(measureSeeMoreLine, debounceSeeMoreCalc);
    return () => clearTimeout(handle);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [mountHiddenTextTwo, seeMoreWidth, collapsedLines, textWidth]);

  useEffect(() => {
    if (!truncatedLineOfImpact) {
      return;
    }

    setMountHiddenTextFour(true);
  }, [truncatedLineOfImpact]);

  useEffect(() => {
    if (
      !(truncatedLineOfImpactWidth || reconciledLineOfImpactWidth) ||
      !seeMoreWidth ||
      !textWidth
    ) {
      return;
    }

    const _width =
      reconciledLineOfImpactWidth || truncatedLineOfImpactWidth || 0;

    let _seeMoreRightPadding = textWidth - _width - seeMoreWidth;
    _seeMoreRightPadding = _seeMoreRightPadding < 0 ? 0 : _seeMoreRightPadding;

    setSeeMoreRightPadding(_seeMoreRightPadding);

    setIsMeasured(true);
  }, [
    truncatedLineOfImpactWidth,
    reconciledLineOfImpactWidth,
    seeMoreWidth,
    textWidth,
  ]);

  useEffect(() => {
    if (!isMeasured || isReady) {
      return;
    }

    const handle = setTimeout(() => {
      setIsReady(true);
      onReady();
    }, debounceSeeMoreCalc);
    return () => clearTimeout(handle);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isMeasured, isReady]);

  return (
    <View style={wrapperStyle}>
      {/* text component to measure see if see more is applicable and get lines */}
      {mountHiddenTextOne && (
        <TextComponent
          {...commonHiddenComponentProps}
          onTextLayout={onTextLayoutOne}>
          {children || ''}
        </TextComponent>
      )}
      {/* text component to measure lines with see less */}
      {mountHiddenTextTwo && (
        <TextComponent
          {...commonHiddenComponentProps}
          onTextLayout={onTextLayoutTwo}>
          {children || ''}
          {/* 3 spaces before see less are intentional */}
          {`   ${seeLessText}`}
        </TextComponent>
      )}
      {/* extract width of line of impact without see more line */}
      {mountHiddenTextFour && (
        <TextComponent
          {...hiddenComponentPropsLineOfImpact}
          onLayout={onLayoutFour}>
          {truncatedLineOfImpact}
        </TextComponent>
      )}
      {mountHiddenTextThree && (
        <TextComponent
          {...commonHiddenComponentProps}
          numberOfLines={numberOfLines}
          ellipsizeMode={'clip'}
          onLayout={onLayoutHiddenTextThree}
          onTextLayout={onTextLayoutHiddenTextThree}>
          {children || ''}
        </TextComponent>
      )}
      {/* extract line of impact with collapsed children for remeasurement of right padding on android */}
      {mountHiddenTextFive && (
        <TextComponent
          {...commonHiddenComponentProps}
          numberOfLines={numberOfLines + 1}
          onLayout={onLayoutHiddenTextFive}
          onTextLayout={onTextLayoutHiddenTextFive}>
          {collapsedChildren || ''}
          {/* no see less here since it's in collapsed state replicating original component */}
        </TextComponent>
      )}
      {/* extract width of reconciled line of impact without see more line */}
      {mountHiddenTextSix && (
        <TextComponent
          {...hiddenComponentPropsLineOfImpact}
          onLayout={onLayoutHiddenTextSix}>
          {reconciledLineOfImpact}
        </TextComponent>
      )}
      {/* actual text component */}
      <TextComponent
        {...additionalProps}
        {...restProps}
        style={style}
        {...textProps}>
        {seeMore && collapsed
          ? collapsedChildren || children || ''
          : children || ''}
        {seeMore && !collapsed && !expandOnly && (
          <TextComponent
            {...additionalProps}
            {...restProps}
            onPress={toggle}
            style={seeLessStyle}>
            {hiddenTextLinesWithSeeLess.length > lines.length ? '\n' : ' '}
            {seeLessText}
          </TextComponent>
        )}
      </TextComponent>
      {/* See more component */}
      {seeMore && collapsed && afterCollapsed && (
        <View
          style={[seeMoreContainerStyle, seeMoreContainerStyleSecondary]}
          onLayout={onSeeMoreViewLayout}>
          {!hideEllipsis && (
            <TextComponent
              key={`${isMeasured}-${hideEllipsis}`}
              {...additionalProps}
              {...restProps}
              onPress={toggle}
              style={[
                style,
                seeMoreTextHidingStyle,
                hideEllipsis ? styles.transparentColor : {},
              ]}>
              {`${ellipsis} `}
            </TextComponent>
          )}
          <TextComponent
            {...additionalProps}
            {...restProps}
            onPress={toggle}
            style={[style, seeMoreStyle, seeMoreTextHidingStyle]}>
            {seeMoreText}
          </TextComponent>
        </View>
      )}
    </View>
  );
}
Example #13
Source File: VLCPlayerView.js    From react-native-vlc with MIT License 4 votes vote down vote up
render() {
    const {
      onEnd,
      style,
      isAd,
      type,
      isFull,
      uri,
      title,
      onLeftPress,
      closeFullScreen,
      showBack,
      showTitle,
      videoAspectRatio,
      showGoLive,
      onGoLivePress,
      onReplayPress,
      titleGolive,
      showLeftButton,
      showMiddleButton,
      showRightButton,
      errorTitle,
      animationLayout,
      videoStyle,
      ...otherProps
    } = this.props;
    const { isLoading, loadingSuccess, showControls, isError } = this.state;

    let showAd = false;
    let realShowLoading = false;
    let source = {};

    if (uri) {
      if (uri.split) {
        source = { uri: this.props.uri };
      } else {
        source = uri;
      }
    }

    if (Platform.OS === 'ios') {
      if ((loadingSuccess && isAd) || (isAd && type === 'swf')) {
        showAd = true;
      }
      if (isLoading && type !== 'swf') {
        realShowLoading = true;
      }
    } else {
      if (loadingSuccess && isAd) {
        showAd = true;
      }
      if (isLoading) {
        realShowLoading = true;
      }
    }

    return (
      <TouchableOpacity
        activeOpacity={1}
        style={[styles.videoBtn, style, videoStyle]}
        onPressOut={() => {
          let currentTime = new Date().getTime();
          if (this.touchTime === 0) {
            this.touchTime = currentTime;
            animationLayout && LayoutAnimation.configureNext(LayoutAnimation.Presets.linear);
            this.setState({ showControls: !this.state.showControls });
          } else {
            if (currentTime - this.touchTime >= 500) {
              this.touchTime = currentTime;
              animationLayout && LayoutAnimation.configureNext(LayoutAnimation.Presets.linear);
              this.setState({ showControls: !this.state.showControls });
            }
          }
        }}>
        <VLCPlayer
          {...otherProps}
          ref={ref => (this.vlcPlayer = ref)}
          paused={this.state.paused}
          style={[styles.video]}
          source={source}
          videoAspectRatio={videoAspectRatio}
          onProgress={this.onProgress.bind(this)}
          onEnd={this.onEnded.bind(this)}
          onStopped={this.onEnded.bind(this)}
          onPlaying={this.onPlaying.bind(this)}
          onBuffering={this.onBuffering.bind(this)}
          onPaused={this.onPaused.bind(this)}
          progressUpdateInterval={250}
          onError={this._onError}
          onOpen={this._onOpen}
          onLoadStart={this._onLoadStart}
        />
        {realShowLoading &&
          !isError && (
            <View style={styles.loading}>
              <ActivityIndicator size={'large'} animating={true} color="#fff" />
            </View>
          )}
        {isError && (
          <View style={[styles.loading, { backgroundColor: '#000' }]}>
            <Text style={{ color: 'red' }}>{errorTitle}</Text>
            <TouchableOpacity
              activeOpacity={1}
              onPress={this._reload}
              style={{
                width: 100,
                alignItems: 'center',
                justifyContent: 'center',
                marginTop: 10,
              }}>
              <Icon name='reload' size={45} color="#fff" />
            </TouchableOpacity>
          </View>
        )}
        <View style={styles.topView}>
          <View style={styles.backBtn}>
            {showBack && (
              <TouchableOpacity
                onPress={() => {
                  if (isFull) {
                    closeFullScreen && closeFullScreen();
                  } else {
                    onLeftPress && onLeftPress();
                  }
                }}
                style={styles.btn}
                activeOpacity={0.8}>
                <Icon name={'chevron-left'} size={30} color="#fff" />
              </TouchableOpacity>
            )}
            <View style={{ justifyContent: 'center', flex: 1, marginRight: 10 }}>
              {showTitle &&
                showControls && (
                  <Text style={{ color: '#fff', fontSize: 16 }} numberOfLines={1}>
                    {title}
                  </Text>
                )}
            </View>
            {showAd && (
              <View style={styles.ad}>
                <TimeLimt
                  onEnd={() => {
                    onEnd && onEnd();
                  }}
                />
              </View>
            )}
          </View>
        </View>
        <View style={[styles.bottomView]}>
          {showControls && (
            <ControlBtn
              showSlider={!isAd}
              showAd={showAd}
              onEnd={onEnd}
              title={title}
              onLeftPress={onLeftPress}
              paused={this.state.paused}
              isFull={isFull}
              currentTime={this.state.currentTime}
              totalTime={this.state.totalTime}
              onPausedPress={this._play}
              onFullPress={this._toFullScreen}
              onValueChange={value => {
                this.changingSlider = true;
                this.setState({
                  currentTime: value,
                });
              }}
              onSlidingComplete={value => {
                this.changingSlider = false;
                if (Platform.OS === 'ios') {
                  this.vlcPlayer.seek(Number((value / this.state.totalTime).toFixed(17)));
                } else {
                  this.vlcPlayer.seek(value);
                }
              }}
              showGoLive={showGoLive}
              onGoLivePress={onGoLivePress}
              onReplayPress={onReplayPress}
              titleGolive={titleGolive}
              showLeftButton={showLeftButton}
              showMiddleButton={showMiddleButton}
              showRightButton={showRightButton}
            />
          )}
        </View>
      </TouchableOpacity>
    );
  }
Example #14
Source File: FileUpload.native.js    From blade with MIT License 4 votes vote down vote up
FileUpload = ({
  title,
  progress,
  fileName,
  fileTypes,
  errorText,
  helpText,
  onFileSelectionError,
  onFileSelected,
  onFileRemoved,
}) => {
  const [file, setFileName] = useState(fileName);
  const hasUploadCompleted = progress >= MAX_PROGRESS_VALUE;

  const handleFileRemoval = () => {
    onFileRemoved();
  };

  useEffect(() => {
    if (fileName) {
      setFileName(fileName);
    } else if (!fileName) {
      setFileName('');
    }
    LayoutAnimation.easeInEaseOut();
  }, [fileName]);

  const handleFilePick = async () => {
    try {
      const document = await DocumentPicker.pick({
        type: !fileTypes
          ? DocumentPicker.types.allFiles
          : Object.keys(DocumentPicker.types).filter((type) => fileTypes.includes(type)),
      });
      setFileName(document.name);
      onFileSelected({
        uri: document.uri,
        type: document.type,
        name: document.name,
        size: document.size,
      });
    } catch (err) {
      if (DocumentPicker.isCancel(err)) {
        // User when cancels the native selection
      } else {
        onFileSelectionError(err);
      }
    }
  };

  return (
    <Size width="100%">
      <View>
        <Size height={6}>
          <Flex alignItems="center" justifyContent="center">
            {file ? (
              <Space padding={[1, 1.5]}>
                <UploadContainer>
                  <Flex flexDirection="row" alignItems="center">
                    <Space margin={[0, 0, 1, 0]}>
                      <View>
                        {hasUploadCompleted && !errorText ? (
                          <Space margin={[0, 1, 0, 0]}>
                            <View>
                              <CheckedCircle size="small" fill="positive.960" />
                            </View>
                          </Space>
                        ) : null}
                        <Flex flex={2}>
                          <View>
                            <Text size="xsmall" color="shade.980">
                              {title}
                            </Text>
                          </View>
                        </Flex>
                        <TouchableOpacity onPress={handleFileRemoval}>
                          <Close size="small" fill="shade.800" />
                        </TouchableOpacity>
                      </View>
                    </Space>
                  </Flex>
                  <ProgressBar size="small" progress={progress} error={errorText} />
                </UploadContainer>
              </Space>
            ) : (
              <Space padding={[1.25, 1.5]}>
                <DashedButton onPress={handleFilePick} activeOpacity={0.7}>
                  <Flex flexDirection="row">
                    <View>
                      <UploadCloud fill="primary.800" size="small" />
                      <Space margin={[0, 0, 0, 0.5]}>
                        <View>
                          <Text size="xsmall" weight="bold" color="primary.800" maxLines={1}>
                            {title}
                          </Text>
                        </View>
                      </Space>
                    </View>
                  </Flex>
                </DashedButton>
              </Space>
            )}
          </Flex>
        </Size>
        {errorText || helpText ? (
          <Space margin={[0.5, 0, 0, 0]}>
            <View>
              <Text size="xsmall" color={errorText ? 'negative.900' : 'shade.950'}>
                {errorText || helpText}
              </Text>
            </View>
          </Space>
        ) : null}
      </View>
    </Size>
  );
}