summaryrefslogtreecommitdiffhomepage
path: root/gui/src/renderer/components
diff options
context:
space:
mode:
authorOskar Nyberg <oskar@mullvad.net>2020-02-15 15:59:26 +0100
committerOskar Nyberg <oskar@mullvad.net>2020-02-18 15:29:44 +0100
commit9f850da5dcafff368604914aff683a20cb502f94 (patch)
tree3ea724b403b1115bcda1a88642c53886f06bab54 /gui/src/renderer/components
parent96a7d0901901dec6b7b3dcc7c5e3d205992aebdd (diff)
downloadmullvadvpn-9f850da5dcafff368604914aff683a20cb502f94.tar.xz
mullvadvpn-9f850da5dcafff368604914aff683a20cb502f94.zip
Display long location names on one line
Diffstat (limited to 'gui/src/renderer/components')
-rw-r--r--gui/src/renderer/components/Marquee.tsx63
-rw-r--r--gui/src/renderer/components/TunnelControl.tsx9
2 files changed, 69 insertions, 3 deletions
diff --git a/gui/src/renderer/components/Marquee.tsx b/gui/src/renderer/components/Marquee.tsx
new file mode 100644
index 0000000000..23fa7d6dcd
--- /dev/null
+++ b/gui/src/renderer/components/Marquee.tsx
@@ -0,0 +1,63 @@
+import * as React from 'react';
+import { Animated, Component, Styles, Types, UserInterface, View } from 'reactxp';
+
+const styles = {
+ text: Styles.createTextStyle({
+ // @ts-ignore
+ width: 'fit-content',
+ whiteSpace: 'nowrap',
+ }),
+};
+
+interface IMarqueeProps {
+ style?: Types.StyleRuleSetRecursive<Types.ButtonStyleRuleSet>;
+}
+
+export default class Marquee extends Component<IMarqueeProps> {
+ private initialLeft = Animated.createValue(0.0);
+ private textAnimation = Styles.createAnimatedTextStyle({ left: this.initialLeft });
+ private textRef = React.createRef<Animated.Text>();
+
+ public componentDidMount() {
+ this.startAnimation();
+ }
+
+ public componentDidUpdate() {
+ this.startAnimation();
+ }
+
+ public render() {
+ return (
+ <View>
+ <Animated.Text
+ ref={this.textRef}
+ style={[styles.text, this.textAnimation, this.props.style]}>
+ {this.props.children}
+ </Animated.Text>
+ </View>
+ );
+ }
+
+ private async startAnimation() {
+ setTimeout(async () => {
+ if (this.textRef.current) {
+ const textLayout = await UserInterface.measureLayoutRelativeToWindow(this.textRef.current);
+ const viewLayout = await UserInterface.measureLayoutRelativeToWindow(this);
+ this.startAnimationImpl(textLayout.width - viewLayout.width, false);
+ }
+ }, 1000);
+ }
+
+ private startAnimationImpl(length: number, reverse: boolean) {
+ if (length >= 0) {
+ Animated.timing(this.initialLeft, {
+ toValue: reverse ? 0.0 : -length,
+ duration: length * 80,
+ delay: 2000,
+ easing: Animated.Easing.Linear(),
+ }).start(() => {
+ this.startAnimationImpl(length, !reverse);
+ });
+ }
+ }
+}
diff --git a/gui/src/renderer/components/TunnelControl.tsx b/gui/src/renderer/components/TunnelControl.tsx
index eba2a3190b..d8a5937760 100644
--- a/gui/src/renderer/components/TunnelControl.tsx
+++ b/gui/src/renderer/components/TunnelControl.tsx
@@ -1,11 +1,12 @@
import * as React from 'react';
-import { Component, Styles, Text, Types, View } from 'reactxp';
+import { Component, Styles, Types, View } from 'reactxp';
import { colors } from '../../config.json';
import { TunnelState } from '../../shared/daemon-rpc-types';
import { messages } from '../../shared/gettext';
import ConnectionPanelContainer from '../containers/ConnectionPanelContainer';
import * as AppButton from './AppButton';
import ImageView from './ImageView';
+import Marquee from './Marquee';
import { IMainButtonProps, ISideButtonProps, MultiButton } from './MultiButton';
import SecuredLabel, { SecuredDisplayStyle } from './SecuredLabel';
@@ -68,8 +69,10 @@ export default class TunnelControl extends Component<ITunnelControlProps> {
const Location = ({ children }: { children?: React.ReactNode }) => (
<View style={styles.status_location}>{children}</View>
);
- const City = () => <Text style={styles.status_location_text}>{this.props.city}</Text>;
- const Country = () => <Text style={styles.status_location_text}>{this.props.country}</Text>;
+ const City = () => <Marquee style={styles.status_location_text}>{this.props.city}</Marquee>;
+ const Country = () => (
+ <Marquee style={styles.status_location_text}>{this.props.country}</Marquee>
+ );
const SwitchLocation = () => {
return (