diff --git a/Design.html b/Design.html new file mode 100644 index 0000000..4ebedaa --- /dev/null +++ b/Design.html @@ -0,0 +1,73 @@ + + + + + + + Document + + + + + +
+
+ +
+
+
+
+ + + +
+ + + +
+
+
+
+ + +
+ Stranger: + Hey! How's it going? +
+
+ You: + Hi! Doing good, thanks! +
+
+ Stranger: + Hey! How's it going? +
+ +
+ You: + Hi! Doing good, thanks! +
+
+ You: + Hi! Doing good, thanks! +
+ +
+
+ + + +
+
+
+ + + + \ No newline at end of file diff --git a/android-chrome-192x192.png b/android-chrome-192x192.png new file mode 100644 index 0000000..e3c8dc9 Binary files /dev/null and b/android-chrome-192x192.png differ diff --git a/android-chrome-512x512.png b/android-chrome-512x512.png new file mode 100644 index 0000000..52c5b57 Binary files /dev/null and b/android-chrome-512x512.png differ diff --git a/apple-touch-icon.png b/apple-touch-icon.png new file mode 100644 index 0000000..d6da6ac Binary files /dev/null and b/apple-touch-icon.png differ diff --git a/chat.html b/chat.html new file mode 100644 index 0000000..9485c62 --- /dev/null +++ b/chat.html @@ -0,0 +1,180 @@ + + + + + + + HeyStranger.live | Stranger Video Calling App + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + Talk To Stanger! +
+
+ 0 online users +
+
+
+ +
+
+ + + + + +
+ + + +
+
+
+
+ + +
+
+
+
+ Stranger: + Hey! How's it going? +
+
+ You: + Hi! Doing good, thanks! +
+
+ Stranger: + Hey! How's it going? +
+ +
+ You: + Hi! Doing good, thanks! +
+
+ Stranger: + Hey! How's it going? +
+
+ You: + Hi! Doing good, thanks! +
+
+ You: + Hi! Doing good, thanks! +
+
+ You: + Hi! Doing good, thanks! +
+
+ You: + Hi! Doing good, thanks! +
+
+ You: + Hi! Doing good, thanks! +
+
+ You: + Hi! Doing good, thanks! +
+
+ You: + Hi! Doing good, thanks! +
+
+ You: + Hi! Doing good, thanks! +
+
+ You: + Hi! Doing good, thanks! +
+
+ You: + Hi! Doing good, thanks! +
+ +
+
+ + + + +
+
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/css/combine.css b/css/combine.css new file mode 100644 index 0000000..43a0881 --- /dev/null +++ b/css/combine.css @@ -0,0 +1,137 @@ +body { + margin: 0; + padding: 0; + /* display: flex; + justify-content: center; + align-items: center; + height: 100vh; */ +} +.chat-box::-webkit-scrollbar { + display: none; + } +.video-container { + position: relative; + /* display: none; */ +} + +video { + width: 100%; + height: 100%; + /* border-radius: 8px; */ + object-fit: cover; + border: 1px solid black; +} + +#local-video { + position: absolute; + height: auto; + top: 10px; + right: 10px; + z-index: 1; + border: 1px solid black; +} + +#controls { + position: absolute; + bottom: 20px; + left: 50%; + transform: translateX(-50%); + background-color: rgba(255, 255, 255, 0.7); + padding: 10px; + border-radius: 8px; + z-index: 2; +} + +button { + margin: 0 5px; + padding: 8px 16px; + border: none; + background-color: #000000; + color: #fff; + border-radius: 4px; + cursor: pointer; +} + +body { + font-family: Arial, sans-serif; + margin: 0; + padding: 0; +} + +.chat-container { + width: 100%; + /* border: 1px solid #ccc; */ + border-radius: 8px; +} + +.chat-box { + padding: 10px; + overflow-y: scroll; + /* max-height: 150px; */ +} +.chat-info{ + margin-bottom: 10px; + padding: 8px; + border-radius: 8px; + color: #007bff; +} +.chat-message { + /* margin-bottom: 10px; */ + padding: 8px; + border-radius: 8px; + /* max-width: 70%; */ + display: flex; + align-items:first baseline + /* justify-content: space-between; */ +} + +.received .message{ + background-color: #f0f0f0; + align-self: flex-start; + padding: 8px; + border-radius: 8px; +} + +.sent .message{ + background-color: #dcf8c6; + align-self: flex-end; + padding: 8px; + border-radius: 8px; +} + +.sender-name { + padding-top: 8px; + font-weight: bold; + margin-right: 5px; +} + +.input-box { + display: flex; + padding: 10px; + /* border-top: 1px solid #ccc; */ + position: sticky; + bottom: 0; + overflow: hidden; +} + +.input-box input { + flex: 1; + padding: 8px; + border: 1px solid #ccc; + border-radius: 4px; +} + +.input-box button { + padding: 8px 20px; + margin-left: 10px; + background-color: #000000; + color: #fff; + border: none; + border-radius: 4px; + cursor: pointer; +} + + +.logo{ + padding:10px 0; +} \ No newline at end of file diff --git a/css/design.css b/css/design.css new file mode 100644 index 0000000..0d74a32 --- /dev/null +++ b/css/design.css @@ -0,0 +1,146 @@ +html, +body { + margin: 0; + padding: 0; +} + +* { + box-sizing: border-box; +} + +/* The mobile-first pre-defined media queries: */ + +/* xs */ +/* @media (min-width: 475px) {} */ + +/* sm */ +/* @media (min-width: 640px) {} */ + +/* md */ +/* @media (min-width: 768px) {} */ + +/* lg */ +/* @media (min-width: 1024px) {} */ + +/* xl */ +/* @media (min-width: 1280px) {} */ +/* Mobile container utility class: */ +.container { + width: 100%; + margin: 0 auto; + /* padding-left: 0.5rem; + padding-right: 0.5rem; */ + /* background-color: blue; */ +} + +#local-video { + width: 160px; +} + +/* hiding the Header if Hieght is less than */ + +@media screen and (max-height:500px) { + /* header{ + display: none; + } */ + .video-container{ + position: fixed; + top:0; + left: 0; + right:0; + display:none; + } + .container{ + width: 100%; + padding: 0; + } +} + + + +/* xs */ +@media (min-width: 475px) { + .container { + max-width: 475px; + } +} + +/* sm */ +@media (min-width: 640px) { + .container { + max-width: 640px; + } +} + +/* md */ +@media (min-width: 768px) { + .container { + max-width: 768px; + } + + .container { + display: grid; + grid-template-columns: 1fr 1fr; + grid-gap: 10px; + } + + .chat-box{ + max-height: 400px; + } + #local-video { + position: static; + } + .video-container{ + display: block; + } +} + +/* lg */ +@media (min-width: 1024px) { + .container { + max-width: 1024px; + } + + .container { + display: grid; + grid-template-columns: 1fr 1fr; + } + + #local-video { + width: 240px; + } +} + +/* xl */ +@media (min-width: 1280px) { + .container { + max-width: 1280px; + } +} + +/* 2xl */ +@media (min-width: 1536px) { + .container { + max-width: 1536px; + } +} + + +/* hiding the Header if Hieght is less than */ + +@media screen and (max-height:500px) { + /* header{ + display: none; + } */ + .video-container{ + position: fixed; + top:0; + left: 0; + right:0; + display:none; + } + .container{ + width: 100%; + padding: 0; + } +} \ No newline at end of file diff --git a/css/indexcss.css b/css/indexcss.css new file mode 100644 index 0000000..ed17697 --- /dev/null +++ b/css/indexcss.css @@ -0,0 +1,40 @@ +.intrests-form{ + display: flex; + flex-direction: row; + justify-content: left; +} +.intrests-form *{ + margin: 0 auto; +} +.buttons-groups{ + margin-top: 15px; + display: flex; + flex-direction: row; + justify-content: left; +} + +.start-chating{ + text-align: center; +} +.buttons-groups p{ + margin: 10px; + padding: 0; +} + +@media screen and (max-width: 600px){ + .intrests-form{ + display: flex; + flex-direction: column; + justify-content: left; + } + .buttons-groups{ + display: flex; + flex-direction: row; + justify-content: left; + } + .buttons-groups p{ + margin: 10px; + padding: 0; + } + +} \ No newline at end of file diff --git a/css/likes.css b/css/likes.css new file mode 100644 index 0000000..3c3bc8a --- /dev/null +++ b/css/likes.css @@ -0,0 +1,57 @@ +.multiple-tags-input{ + margin:10px 0; +} +.multiple-tags-input h3{ + margin: 0 0 10px; + padding: 0; +} +.multiple-tags-input .tags-input { + background-color: #fff; + border: 1px solid #ccc; + border-radius: 5px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + padding: 5px; + width: 300px; + } + + .multiple-tags-input .tag-input-field { + border: 1px solid #ccc; + border-radius: 5px; + padding: 5px; + width: 100%; + box-sizing: border-box; + outline: none; + font-size: 16px; + width: 100%; + } + + .multiple-tags-input .tags-list { + display: flex; + flex-wrap: wrap; + padding: 5px 0; + } + + .multiple-tags-input .tag { + background-color: #007bff; + color: #fff; + border-radius: 3px; + padding: 2px 10px; + margin: 2px; + display: flex; + align-items: center; + transition: background-color 0.3s; + } + + .multiple-tags-input .tag:hover { + background-color: #0056b3; + } + + .multiple-tags-input .tag-close-btn { + cursor: pointer; + margin-left: 5px; + font-weight: bold; + } + + .multiple-tags-input .tag-close-btn:hover { + color: #ff0000; + } \ No newline at end of file diff --git a/css/main.css b/css/main.css new file mode 100644 index 0000000..19d8e67 --- /dev/null +++ b/css/main.css @@ -0,0 +1,320 @@ +:root{ + --height: 80vh; +} +body { + font-family: Arial, sans-serif; + margin: 0; + padding: 0; + background-color: #f3f3f3; + color: #333; +} + +/* Container styles */ +.container { + /* max-width: 800px; */ + margin: 20px auto; + padding: 20px; + background-color: #fff; + border-radius: 10px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); +} + +.main { + display: flex; + flex-direction: column; justify-content:space-evenly; +} +#video-containers{ + width: 100%; + margin-right: 10px; +} + + +/* Video styles */ +video { + background-color: #000; + /* width: 320px; + height: 240px; */ + /* width: 640px; + height: 480px; */ + height: 35vh; + width: 100%; + margin-bottom: 10px; + border-radius: 5px; + display: block; +} + +/* Table styles */ +table { + width: 100%; + border-collapse: collapse; + margin-bottom: 20px; +} + +th, +td { + padding: 10px; + border-bottom: 1px solid #ddd; +} + +th { + text-align: left; + font-weight: bold; + background-color: #f9f9f9; +} + +/* Chat box styles */ +.chat-box { + /* display: ; */ + border: 1px solid #ddd; + border-radius: 5px; + background-color: #fff; + margin-bottom: 20px; + height: var(--height); + box-sizing: border-box; + position: relative; +} + +.chat-box-header { + padding: 10px; + border-bottom: 1px solid #ddd; + background-color: #f9f9f9; + border-radius: 5px 5px 0 0; +} + +.chat-box-header h3 { + margin: 0; +} + +.chat-box-body { + padding: 10px; + max-height: 80%; + overflow-y: scroll; + box-sizing: border-box; +} + +.chat-message { + margin-bottom: 5px; + overflow: hidden; +} + +.chat-box-footer { + position: absolute; + bottom: 0; + left: 0; + right: 0; + display: flex; + flex-direction: row; + box-sizing: border-box; + padding: 10px; + border-top: 1px solid #ddd; + border-radius: 0 0 5px 5px; +} + +#is-typing { + font-style: italic; + color: #777; +} + +#message-input { + width: calc(100% - 80px); + padding: 5px; + border: 1px solid #ddd; + border-radius: 3px; + margin-right: 5px; + font-size: 16px; +} + +#send-btn { + padding: 10px 14px; + background-color: #333; + color: #fff; + border: none; + border-radius: 3px; + cursor: pointer; +} + +#send-btn:hover { + background-color: #555; +} + +/* Tags input styles */ +.multiple-tags-input { + margin-bottom: 20px; +} + +.tags-input { + border: 1px solid #ddd; + border-radius: 5px; + padding: 10px; +} + +.tags-list { + display: flex; + flex-wrap: wrap; + margin-bottom: 5px; +} + +.tag { + background-color: #f2f2f2; + padding: 3px 7px; + margin-right: 5px; + margin-bottom: 5px; + border-radius: 3px; +} + +.tag-remove { + margin-left: 5px; + cursor: pointer; +} + +.tag-input-field { + border: none; + outline: none; + background: transparent; + margin-bottom: 5px; + width: 100%; +} + +.tag-input-field:focus { + border: 1px solid #777; +} + +/* Button styles */ + +button { + padding: 10px 20px; + background-color: #333; + color: #fff; + border: none; + border-radius: 5px; + cursor: pointer; + margin-right: 10px; +} + +button:hover { + background-color: #555; +} + +/* Styling for the local video container */ +.local-video-container { + position: relative; + width: 100%; + /* Adjust width as needed */ +} + +/* Styling for the mute buttons */ +#mute-audio, +#mute-video { + position: absolute; + bottom: 10px; + /* Adjust vertical position as needed */ + right: 10px; + /* Adjust horizontal position as needed */ + background-color: rgba(0, 0, 0, 0.5); + /* Semi-transparent background */ + color: white; + border: none; + padding: 5px 10px; + cursor: pointer; + z-index: 1; + margin-right: 10px; + /* Ensure buttons are above the video */ +} + +#mute-audio { + right: 100px; +} + +/* Optional: Hover effect for buttons */ +#mute-audio:hover, +#mute-video:hover { + background-color: rgba(255, 255, 255, 0.5); + /* Semi-transparent background on hover */ + color: black; +} + +/* Styling for the local video container */ +.remote-video-container { + position: relative; + width: 100%; + /* Adjust width as needed */ +} + +/* Styling for the text */ +.remote-video-container h4 { + margin:0; + position: absolute; + bottom: 10px; + /* Adjust vertical position as needed */ + right: 10px; + /* Adjust horizontal position as needed */ + background-color: rgba(0, 0, 0, 0.5); + /* Semi-transparent background */ + color: white; + border: none; + padding: 5px 10px; + cursor: pointer; + z-index: 1; + margin-right: 10px; + /* Ensure buttons are above the video */ +} + +.header { + background-color: #f2f2f2; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* Adding box shadow */ +} + +.header .header-container { + display: flex; + justify-content: space-between; + align-items: center; + background-color: #fff; + padding: 10px 20px; +} + +.logo img { + max-width: 200px; /* Adjust the max-width as needed */ + cursor: pointer; +} +.logo h1{ + font-size: 22px; + margin: 0; + padding: 0; +} + +.middle-info { + font-size: small; + /* flex-grow: 6; Allow this div to take up remaining space */ +} + +.info p { + margin: 0; +} + + + +/* Default styles for all screen sizes */ +.container { + width: 100%; +} + +/* Styles for screens smaller than 768px (e.g., smartphones) */ +@media (max-width: 767px) { + .container { + width: 90%; /* Adjusting width for smaller screens */ + } +} + +/* Styles for screens between 768px and 991px (e.g., tablets) */ +@media (min-width: 768px) and (max-width: 991px) { + .container { + width: 80%; /* Adjusting width for medium-sized screens */ + } +} + +/* Styles for screens larger than 992px (e.g., desktops) */ +@media (min-width: 992px) { + .container { + width: 70%; /* Adjusting width for larger screens */ + } +} diff --git a/css/material-icons.woff2 b/css/material-icons.woff2 new file mode 100644 index 0000000..5492a6e Binary files /dev/null and b/css/material-icons.woff2 differ diff --git a/css/style.css b/css/style.css new file mode 100644 index 0000000..457ad93 --- /dev/null +++ b/css/style.css @@ -0,0 +1,636 @@ +/* +! tailwindcss v3.4.1 | MIT License | https://tailwindcss.com +*/ + +/* +1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) +2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) +*/ + +*, +::before, +::after { + box-sizing: border-box; + /* 1 */ + border-width: 0; + /* 2 */ + border-style: solid; + /* 2 */ + border-color: #e5e7eb; + /* 2 */ +} + +::before, +::after { + --tw-content: ''; +} + +/* +1. Use a consistent sensible line-height in all browsers. +2. Prevent adjustments of font size after orientation changes in iOS. +3. Use a more readable tab size. +4. Use the user's configured `sans` font-family by default. +5. Use the user's configured `sans` font-feature-settings by default. +6. Use the user's configured `sans` font-variation-settings by default. +7. Disable tap highlights on iOS +*/ + +html, +:host { + line-height: 1.5; + /* 1 */ + -webkit-text-size-adjust: 100%; + /* 2 */ + -moz-tab-size: 4; + /* 3 */ + -o-tab-size: 4; + tab-size: 4; + /* 3 */ + font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + /* 4 */ + font-feature-settings: normal; + /* 5 */ + font-variation-settings: normal; + /* 6 */ + -webkit-tap-highlight-color: transparent; + /* 7 */ +} + +/* +1. Remove the margin in all browsers. +2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. +*/ + +body { + margin: 0; + /* 1 */ + line-height: inherit; + /* 2 */ +} + +/* +1. Add the correct height in Firefox. +2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) +3. Ensure horizontal rules are visible by default. +*/ + +hr { + height: 0; + /* 1 */ + color: inherit; + /* 2 */ + border-top-width: 1px; + /* 3 */ +} + +/* +Add the correct text decoration in Chrome, Edge, and Safari. +*/ + +abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} + +/* +Remove the default font size and weight for headings. +*/ + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: inherit; + font-weight: inherit; +} + +/* +Reset links to optimize for opt-in styling instead of opt-out. +*/ + +a { + color: inherit; + text-decoration: inherit; +} + +/* +Add the correct font weight in Edge and Safari. +*/ + +b, +strong { + font-weight: bolder; +} + +/* +1. Use the user's configured `mono` font-family by default. +2. Use the user's configured `mono` font-feature-settings by default. +3. Use the user's configured `mono` font-variation-settings by default. +4. Correct the odd `em` font sizing in all browsers. +*/ + +code, +kbd, +samp, +pre { + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + /* 1 */ + font-feature-settings: normal; + /* 2 */ + font-variation-settings: normal; + /* 3 */ + font-size: 1em; + /* 4 */ +} + +/* +Add the correct font size in all browsers. +*/ + +small { + font-size: 80%; +} + +/* +Prevent `sub` and `sup` elements from affecting the line height in all browsers. +*/ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* +1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) +2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) +3. Remove gaps between table borders by default. +*/ + +table { + text-indent: 0; + /* 1 */ + border-color: inherit; + /* 2 */ + border-collapse: collapse; + /* 3 */ +} + +/* +1. Change the font styles in all browsers. +2. Remove the margin in Firefox and Safari. +3. Remove default padding in all browsers. +*/ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; + /* 1 */ + font-feature-settings: inherit; + /* 1 */ + font-variation-settings: inherit; + /* 1 */ + font-size: 100%; + /* 1 */ + font-weight: inherit; + /* 1 */ + line-height: inherit; + /* 1 */ + color: inherit; + /* 1 */ + margin: 0; + /* 2 */ + padding: 0; + /* 3 */ +} + +/* +Remove the inheritance of text transform in Edge and Firefox. +*/ + +button, +select { + text-transform: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Remove default button styles. +*/ + +button, +[type='button'], +[type='reset'], +[type='submit'] { + -webkit-appearance: button; + /* 1 */ + background-color: transparent; + /* 2 */ + background-image: none; + /* 2 */ +} + +/* +Use the modern Firefox focus style for all focusable elements. +*/ + +:-moz-focusring { + outline: auto; +} + +/* +Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) +*/ + +:-moz-ui-invalid { + box-shadow: none; +} + +/* +Add the correct vertical alignment in Chrome and Firefox. +*/ + +progress { + vertical-align: baseline; +} + +/* +Correct the cursor style of increment and decrement buttons in Safari. +*/ + +::-webkit-inner-spin-button, +::-webkit-outer-spin-button { + height: auto; +} + +/* +1. Correct the odd appearance in Chrome and Safari. +2. Correct the outline style in Safari. +*/ + +[type='search'] { + -webkit-appearance: textfield; + /* 1 */ + outline-offset: -2px; + /* 2 */ +} + +/* +Remove the inner padding in Chrome and Safari on macOS. +*/ + +::-webkit-search-decoration { + -webkit-appearance: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Change font properties to `inherit` in Safari. +*/ + +::-webkit-file-upload-button { + -webkit-appearance: button; + /* 1 */ + font: inherit; + /* 2 */ +} + +/* +Add the correct display in Chrome and Safari. +*/ + +summary { + display: list-item; +} + +/* +Removes the default spacing and border for appropriate elements. +*/ + +blockquote, +dl, +dd, +h1, +h2, +h3, +h4, +h5, +h6, +hr, +figure, +p, +pre { + margin: 0; +} + +fieldset { + margin: 0; + padding: 0; +} + +legend { + padding: 0; +} + +ol, +ul, +menu { + list-style: none; + margin: 0; + padding: 0; +} + +/* +Reset default styling for dialogs. +*/ + +dialog { + padding: 0; +} + +/* +Prevent resizing textareas horizontally by default. +*/ + +textarea { + resize: vertical; +} + +/* +1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) +2. Set the default placeholder color to the user's configured gray 400 color. +*/ + +input::-moz-placeholder, textarea::-moz-placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +input::placeholder, +textarea::placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +/* +Set the default cursor for buttons. +*/ + +button, +[role="button"] { + cursor: pointer; +} + +/* +Make sure disabled buttons don't get the pointer cursor. +*/ + +:disabled { + cursor: default; +} + +/* +1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) +2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) + This can trigger a poorly considered lint error in some tools but is included by design. +*/ + +img, +svg, +video, +canvas, +audio, +iframe, +embed, +object { + display: block; + /* 1 */ + vertical-align: middle; + /* 2 */ +} + +/* +Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) +*/ + +img, +video { + max-width: 100%; + height: auto; +} + +/* Make elements with the HTML hidden attribute stay hidden by default */ + +[hidden] { + display: none; +} + +*, ::before, ::after { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; +} + +::backdrop { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; +} + +.container { + width: 100%; +} + +@media (min-width: 640px) { + .container { + max-width: 640px; + } +} + +@media (min-width: 768px) { + .container { + max-width: 768px; + } +} + +@media (min-width: 1024px) { + .container { + max-width: 1024px; + } +} + +@media (min-width: 1280px) { + .container { + max-width: 1280px; + } +} + +@media (min-width: 1536px) { + .container { + max-width: 1536px; + } +} + +.mx-auto { + margin-left: auto; + margin-right: auto; +} + +.flex { + display: flex; +} + +.hidden { + display: none; +} + +.border { + border-width: 1px; +} + +.bg-black { + --tw-bg-opacity: 1; + background-color: rgb(0 0 0 / var(--tw-bg-opacity)); +} + +.bg-rose-800 { + --tw-bg-opacity: 1; + background-color: rgb(159 18 57 / var(--tw-bg-opacity)); +} + +.bg-inherit { + background-color: inherit; +} + +.bg-rose-600 { + --tw-bg-opacity: 1; + background-color: rgb(225 29 72 / var(--tw-bg-opacity)); +} + +.from-red-600 { + --tw-gradient-from: #dc2626 var(--tw-gradient-from-position); + --tw-gradient-to: rgb(220 38 38 / 0) var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); +} + +.text-lg { + font-size: 1.125rem; + line-height: 1.75rem; +} + +.text-2xl { + font-size: 1.5rem; + line-height: 2rem; +} + +.text-white { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); +} \ No newline at end of file diff --git a/css/test.css b/css/test.css new file mode 100644 index 0000000..5a5d968 --- /dev/null +++ b/css/test.css @@ -0,0 +1,630 @@ +:root { + /* Colors */ + --primary-color: #007bff; + /* blue */ + --secondary-color: #6c757d; + /* gray */ + --success-color: #28a745; + /* green */ + --info-color: #17a2b8; + /* cyan */ + --warning-color: #ffc107; + /* yellow */ + --danger-color: #dc3545; + /* red */ + --light-color: #f8f9fa; + /* light gray */ + --dark-color: #343a40; + /* dark gray */ + + /* Background and Text Colors */ + --background-color: #fff; + /* default background color */ + --text-color: #000; + /* default text color */ +} + +/* Dark Mode */ +.dark-mode { + /* Colors */ + --primary-color: #0d6efd; + /* blue */ + --secondary-color: #b3b3b3; + /* gray */ + --success-color: #198754; + /* green */ + --info-color: #0dcaf0; + /* cyan */ + --warning-color: #ffc107; + /* yellow */ + --danger-color: #dc3545; + /* red */ + --light-color: #212529; + /* light gray */ + --dark-color: #f8f9fa; + /* dark gray */ + + /* Background and Text Colors */ + --background-color: #212529; + /* dark mode background color */ + --text-color: #fff; + /* dark mode text color */ +} + + +/* fallback +@font-face { + font-family: 'Material Icons'; + font-style: normal; + font-weight: 400; + src: url(./material-icons.woff2) format('woff2'); + } + + .material-icons { + font-family: 'Material Icons'; + font-weight: normal; + font-style: normal; + font-size: 24px; + line-height: 1; + letter-spacing: normal; + text-transform: none; + display: inline-block; + white-space: nowrap; + word-wrap: normal; + direction: ltr; + -webkit-font-feature-settings: 'liga'; + -webkit-font-smoothing: antialiased; + } */ + + +/************************** + REAT CODE CSSS + *************************/ + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + margin: 0; + padding: 0; + font-family: Arial, sans-serif; + background-color: var(--dark-color); + color: var(--light-color); +} + + +/************************** + LAYOUT CSSS + *************************/ +.mobile .container { + height: 100vh; + display: grid; + grid-template-columns: 1fr; + grid-template-rows: 1rf 1fr; + position: relative; +} + +.bottom-sheet { + max-height: calc(100vh - 100px); +} + +.chat { + /* max-height: calc(80vh - 140px); */ +} + + +.container { + margin: 0 auto; +} + +/* xs */ +@media (min-width: 475px) { + .container { + max-width: 100%; + } +} + +/* sm */ +@media (min-width: 640px) { + .container { + max-width: 100%; + } +} + +/* md */ +@media (min-width: 768px) { + .container { + max-width: 768px; + } +} + +/* lg */ +@media (min-width: 1024px) { + .container { + max-width: 1024px; + } + + .moblie .container { + grid-template-columns: 600px 1fr; + } +} + +/* xl */ +@media (min-width: 1280px) { + .container { + max-width: 1280px; + } +} + +/* 2xl */ +@media (min-width: 1536px) { + .container { + max-width: 1536px; + } +} + + +/************************** + HEADER STYLING + *************************/ + + +/* Header styles */ +header { + margin: 0 auto; + background-color: var(--dark-color); + color: var(--light-color); + /* box-shadow: 0px 0px 3px #ccc; */ + border-radius: 7px; +} + +header .container { + + /* color: #fff; */ + padding: 15px 20px; + display: flex; + justify-content: space-between; + align-items: center; + z-index: 100; + +} + +/* Logo styles */ +.logo a { + font-size: 24px; + font-weight: bold; + display: flex; + flex-direction: row; + align-items: center; + text-decoration: none; + color: var(--light-color); +} + +.logo h2 { + margin: 0; + padding: 0; + font-size: 1.5rem; + cursor: pointer; + font-family: cursive; + margin-left: 5px; +} + +/* Navigation styles */ +nav { + display: flex; +} + +nav ul { + list-style-type: none; + margin: 0; + padding: 0; + display: flex; +} + +nav li { + margin-right: 20px; +} + +nav a { + /* color: #fff; */ + text-decoration: none; + transition: color 0.3s; +} + +nav a:hover { + /* color: #ccc; */ +} + +/* Hamburger menu styles */ +.menu-toggle { + display: none; + cursor: pointer; +} + +/* Responsive styles */ +@media (max-width: 768px) { + .logo { + font-size: 20px; + } + + nav { + display: none; + flex-direction: column; + } + + nav.active { + display: flex; + } + + .menu-toggle { + display: block; + } + + .menu-toggle:hover { + /* color: #ccc; */ + } +} + + +/************************** + VIDEO CONTAINER CSS + *************************/ + +.video-container { + position: relative; + width: 100%; + overflow: hidden; + box-sizing: border-box; +} + +video { + background-color: var(--text-color); +} + +.video-container .remote-video-container #remote-video { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + object-fit: cover; + aspect-ratio: 4/3; + /* background-image: url("../img/image.png") !important; + background-size: 100% auto !important; + background-size: cover !important; + background-position: center !important; */ +} + +.video-container .local-video-container { + position: absolute; + top: 15px; + right: 15px; + width: 60px; + height: calc(60px * (4/3)); + z-index: 5; + border: 3px solid #ccc; + /* border-radius: 7px; */ + aspect-ratio: 4/3; +} + +.video-container .local-video-container #local-video { + top: 5px; + right: 5px; + width: 100%; + height: 100%; + z-index: 66; + object-fit: cover; +} + + + + +.controls { + position: absolute; + bottom: 100px; + display: grid; + grid-template-rows: 1fr 1fr 1fr; + right: 10px; + /* background-color: var(--dark-color); */ + /* Semi-transparent background for controls */ + + padding: 7px; + box-sizing: border-box; + border-radius: 5px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + gap: 5px; + +} + +.controls button { + color: var(--light-color); + border: none; + cursor: pointer; + padding: 5px; + /* margin-right: 5px; */ + font-size: 16px; + background-color: #ccc; + border-radius: 50%; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + color: #000; + box-shadow: 0 0 5px rgba(0, 0, 0, 0.2); +} + +/************************** + CHATBOX STYLING + *************************/ + +.bottom-sheet { + position: fixed; + /* border-radius: 20px 20px 0 0; */ + bottom: -100%; + /* Start hidden */ + left: 0; + width: 100%; + height: 52vh; + max-height: calc(100% - 50px); + /* Set maximum height to prevent overflowing */ + color: var(--light-color); + transition: bottom 0.3s ease-out; + /* Animation effect */ + box-shadow: 0px -4px 8px rgba(0, 0, 0, 0.2); + /* Optional: Add shadow */ + overflow-y: auto; + z-index: 999; + /* Enable vertical scrolling if content exceeds height */ + background-color: var(--dark-color); +} + +.handle-bar { + width: 100%; + height: 20px; + background-color: transparent; + cursor: pointer; + position: relative; +} + +.handle-bar::before { + content: ''; + position: absolute; + top: 20px; + left: 50%; + transform: translate(-50%, -50%); + width: 40px; + height: 5px; + background-color: #ccc; + border-radius: 2px; +} + +/* .bottom-sheet-content { + padding: 20px; +} */ + +.show-bottom-sheet { + bottom: 0; + /* Show the bottom sheet */ +} + + +.chat-container { + display: flex; + flex-direction: column; + margin-top: 10px; + /* height: 50vh; */ +} + +.chat::-webkit-scrollbar { + display: none; +} + +.chat { + /* flex: 1; */ + overflow-y: auto; + padding: 10px; + height: 35vh; + /* max-height: calc(100% - 20px); */ +} + +.message { + display: flex; + align-items: flex-end; + margin-bottom: 10px; + color: var(--text-color); +} +/* .message:last-child::after { + content: "typing..."; + display: block; + position: absolute; + top:100%; + bottom:7px; + margin-top: 5px; + color: var(--light-color); +} */ +.received { + justify-content: flex-start; +} + +.sent { + justify-content: flex-end; +} + +.sent .message-text { + background-color: var(--info-color); + border-radius: 10px 10px 0 10px; +} + +.received .message-text { + background-color: #f1f1f1; + border-radius: 10px 10px 10px 0; +} + +.avatar { + display: none; + justify-content: center; + align-items: center; + width: 40px; + height: 40px; + border-radius: 50%; + background-color: #ccc; + /* Placeholder color */ + margin-right: 10px; +} + + +.message-text { + max-width: 70%; + background-color: #f1f1f1; + padding: 10px; + border-radius: 10px; +} + +.input-container { + display: flex; + align-items: center; + padding: 10px; + background-color: var(--dark-color); + bottom: 0; +} + +#message-input { + flex: 1; + padding: 10px; + border: none; + border-radius: 15px; + margin-right: 10px; + background-color: inherit; + border: 1px solid #6c757d; + color: var(--light-color); +} + +#send-btn, +#esc-btn { + padding: 8px; + background-color: var(--text-color); + color: #fff; + border: none; + border-radius: 15px; + cursor: pointer; + outline: none; + display: flex; + justify-content: center; + align-items: center; +} + +#send-btn { + padding: 8px 10px; +} + +.message { + position: relative; + margin-bottom: 10px; +} + +.message-info { + text-align: center; + padding: 10px; + margin: 10px; +} + +/************************** + LAYOUT + *************************/ + + +/************************** + RESPONSIVENESS + *************************/ + +@media screen and (min-width:768px) { + .video-container { + overflow: visible; + } + + .video-container .remote-video-container #remote-video { + position: static; + width: 100%; + height: 40vh; + object-fit: cover; + } + + .video-container .remote-video-container { + margin-top: 10px; + /* border-radius: 10px; */ + overflow: hidden; + } + + .video-container .local-video-container { + position: static; + width: 100%; + height: auto; + height: 40vh; + border: none; + /* border-radius: 10px; */ + overflow: hidden; + } + + .video-container .remote-video-container, + .video-container .local-video-container { + background-color: var(--text-color); + border-radius: 10px; + border: 1px solid #ccc; + } + + .bottom-sheet-content { + height: 100%; + } + + .mobile .container { + display: grid; + /* grid-column-gap: 25px; */ + grid-template-columns: 400px 1fr; + /* grid-template-rows: 1rf; */ + height: calc(100vh - 130px); + align-items: stretch; + box-shadow: none; + margin-top: 15px; + } + + .bottom-sheet { + position: static; + max-height: 100%; + border-radius: 0; + box-shadow: 0; + height: 100%; + } + + .chat-container { + margin-top: 0; + height: 100%; + overflow: hidden; + display: flex; + /* justify-content: center; + align-items: center; */ + } + + .chat-container .chat-container { + padding: 0 20px; + } + + .handle-bar { + display: none; + } + + .chat { + height: inherit; + /* background-color: #6c757d; */ + padding: 20px; + overflow: scroll; + } + #esc-main-text{ + margin-top: 5px; + } +} \ No newline at end of file diff --git a/favicon-16x16.png b/favicon-16x16.png new file mode 100644 index 0000000..c7d161c Binary files /dev/null and b/favicon-16x16.png differ diff --git a/favicon-32x32.png b/favicon-32x32.png new file mode 100644 index 0000000..3f5ed16 Binary files /dev/null and b/favicon-32x32.png differ diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000..f9f78e7 Binary files /dev/null and b/favicon.ico differ diff --git a/img/image.png b/img/image.png new file mode 100644 index 0000000..ec27dff Binary files /dev/null and b/img/image.png differ diff --git a/img/log4.png b/img/log4.png new file mode 100644 index 0000000..b608d36 Binary files /dev/null and b/img/log4.png differ diff --git a/img/logo.png b/img/logo.png new file mode 100644 index 0000000..fd091d0 Binary files /dev/null and b/img/logo.png differ diff --git a/img/logo1.png b/img/logo1.png new file mode 100644 index 0000000..128d1e7 Binary files /dev/null and b/img/logo1.png differ diff --git a/img/logo2.png b/img/logo2.png new file mode 100644 index 0000000..6d733f1 Binary files /dev/null and b/img/logo2.png differ diff --git a/img/refresh.png b/img/refresh.png new file mode 100644 index 0000000..b61923b Binary files /dev/null and b/img/refresh.png differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..70f30ee --- /dev/null +++ b/index.html @@ -0,0 +1,177 @@ + + + + + + + HeyStranger.live | Stranger Video Calling App + + + + + + + + + + + + + +
+
+ +
+ + Talk To Stanger! +
+
+ 500+ online users +
+
+
+ +
+

+ You don't need an app to use HeyStranger on your phone or tablet! The site works well on mobile devices. +

+

HeyStranger is a great way to meet new people. When you use HeyStranger, we randomly select another person and chat with you one-on-one. To ensure your security, chats are anonymous unless you tell someone who you are (not recommended!) and you can end the chat at any time. Predators have been known to use HeyStranger, so be careful.

+

You can add your interests if you want and HeyStranger will find people who share your interests rather than completely random people.

+

+ Your use of HeyStranger constitutes your acceptance of these .Terms and Conditions. +

+
+
+

What do you talk about?

+
+
+ +
+
+
+

Start Chat

+
+ + +

Or

+ +
+
+
+

+ This Services Agreement (“Agreement” or “Terms”) constitutes a legal contract between you and HeyStranger.live, LLC (“HeyStranger”, “us” or “our”). By accessing or using the HeyStranger website currently located at HeyStranger.live (the “Site”) or any applications or other services provided or operated by HeyStranger (collectively, the “Services”), you may indicate your acceptance of such services by clicking on the following icon: check box By using the or button you confirm that you have read, understood and agree to be bound by these terms. If you do not agree to these Terms, please do not access or use the Services. +

+ + + + + +
+ + + + + \ No newline at end of file diff --git a/js/chat.js b/js/chat.js new file mode 100644 index 0000000..6fc6099 --- /dev/null +++ b/js/chat.js @@ -0,0 +1,141 @@ +/***************************************** + * REfacted in another way + ****************************************/ +import { MessageBox, chatBody, SendMessage } from "./elements.js"; + +const escMainText = document.getElementById("esc-main-text"); + +const handelDataChannel = (dataChannel, partnerIntrests) => { + document.getElementById(MessageBox).disabled = true; + console.log("handeling data channel:", dataChannel, partnerIntrests) + dataChannel.onopen = () => { + document.getElementById(MessageBox).disabled = false; + if (chatBody) { + var urlParams = new URLSearchParams(window.location.search); + var arrayParam = urlParams.get('tags'); + let yourslikes = JSON.parse(decodeURIComponent(arrayParam)); + chatBody.innerHTML =""; + // chatBody.innerHTML = "You're now chatting with a random stranger. Say hi!"; + // chatBody.innerHTML += `
You're now chatting with a random stranger.
`; + if ((yourslikes && yourslikes.length > 0) && (partnerIntrests && partnerIntrests.length > 0)) { + const coomonIntrest = partnerIntrests.filter(value => yourslikes.includes(value)); + chatBody.innerHTML += `
You both likes:${coomonIntrest.map((like) => "" + like + "")} .
`; + } else { + chatBody.innerHTML += `
You are cnnected with a completly random stranger.
`; + } + + // if(yourslikes && yourslikes.length>0){ + // chatBody.innerHTML += `
Your's likes:${yourslikes.map((like)=> ""+like+"")} .
`; + + // } + // if(partnerIntrests && partnerIntrests.length>0){ + // chatBody.innerHTML += `
Stranger's likes:${partnerIntrests.map((like)=> ""+like+"")} .
`; + + // } + + + } + + if (escMainText) { + escMainText.textContent = "Click to disconnect"; + } + } + dataChannel.onmessage = (e) => { + console.log("Message:", e.data); + let data = JSON.parse(e.data); + if (chatBody) { + if (data.type == "chat") { + chatBody.innerHTML += `
+
S
+
${data.content}
+
`; + escMainText.textContent = "Click to disconnect"; + chatBody.scrollTop = chatBody.scrollHeight; + } + else if (data.type == "typing") { + if (data.isTyping) { + escMainText.textContent = "Stranger is typing..."; + } + else { + escMainText.textContent = "Click to disconnect"; + } + } + + } else { + alert("Chat Box Not Found"); + } + } + dataChannel.onclose = () => { + console.log("Data channel is closed"); + document.getElementById(MessageBox).disabled = true; + if (chatBody) { + chatBody.innerHTML += " Stranger is Disconnected..."; + chatBody.scrollTop = chatBody.scrollHeight; + } + if (escMainText) { + escMainText.textContent = "Click to connect"; + } + } + dataChannel.onerror = (e) => { + console.error("Data channel error:", e); + } + + const chatInput = document.getElementById(MessageBox); + const sendBtn = document.getElementById(SendMessage); + const clonedChatInput = chatInput.cloneNode(true); + chatInput.parentNode.replaceChild(clonedChatInput, chatInput); + const clonedSendBtn = sendBtn.cloneNode(true); + sendBtn.parentNode.replaceChild(clonedSendBtn, sendBtn); + + // Add event listeners to the cloned elements + if (clonedChatInput && clonedSendBtn && chatBody) { + clonedChatInput.addEventListener('keydown', function (event) { + const tagText = event.target.value.trim(); + if (event.key === 'Enter' && tagText !== '') { + dataChannel.send(JSON.stringify({ type: "chat", content: clonedChatInput.value })); // Assuming dataChannel is defined somewhere + chatBody.innerHTML += `
+
${clonedChatInput.value}
+
`; + clonedChatInput.value = ""; + chatBody.scrollTop = chatBody.scrollHeight; + clonedChatInput.focus(); + + } + }); + + clonedSendBtn.addEventListener("click", () => { + const tagText = clonedChatInput.value.trim(); + if (tagText !== '') { + dataChannel.send(JSON.stringify({ type: "chat", content: clonedChatInput.value })); // Assuming dataChannel is defined somewhere + chatBody.innerHTML += `
+
${clonedChatInput.value}
+
`; + clonedChatInput.value = ""; + chatBody.scrollTop = chatBody.scrollHeight; + clonedChatInput.focus(); + } + }); + } + + let typingTimeout; // Variable to store typing timeout + + // Function to send typing indicator when user starts typing + function startTyping() { + if (!typingTimeout) { + dataChannel.send(JSON.stringify({ type: 'typing', isTyping: true })); + } else { + clearTimeout(typingTimeout); + } + + // Set timeout to send typing indicator after a delay when user stops typing + typingTimeout = setTimeout(() => { + dataChannel.send(JSON.stringify({ type: 'typing', isTyping: false })); + typingTimeout = null; + }, 1000); // Adjust the delay as needed + } + clonedChatInput.addEventListener('input', () => { + startTyping(); + }); +} + +export { handelDataChannel } \ No newline at end of file diff --git a/js/elements.js b/js/elements.js new file mode 100644 index 0000000..96020c2 --- /dev/null +++ b/js/elements.js @@ -0,0 +1,48 @@ +/***************************************************************************** * + * STRUCTURE WILL BE DEFINED HERE + * 1. get all the nessasery document to changess + * (i) local-video , remote-video + * (ii) chat body + * (III) All Chats + * +******************************************************************************* */ + +// All Impotant Element; + +let STRUCTURE = { + RemoteVideo : "remote-video", // Remote Video + LocalVideo : "local-video", // Local Video + MuteVideo : "video-button", // Mute/Unmute Video + MuteAudio : "mute-button", // Mute/Unmute Audio + Chats : { + ChatBody : "chat", // Chat Body + ConnectDisconnect: "esc-btn", // Connect/Disconnect button + SendMessage : "send-btn", // Send button + MessageBox : "message-input", // Input for Message + TypingIndicator: "is-typing" // typing Indicator + }, + Info :{ + TotalUsers:"total-users" // Total Users Info + } + +} +let COMPONENT = { + remoteVideo: document.getElementById(STRUCTURE.RemoteVideo), + localVideo: document.getElementById(STRUCTURE.LocalVideo), + muteVideoButton: document.getElementById(STRUCTURE.MuteVideo), + muteAudioButton: document.getElementById(STRUCTURE.MuteAudio), + chatBody: document.getElementById(STRUCTURE.Chats.ChatBody), + connectDisconnectButton: document.getElementById(STRUCTURE.Chats.ConnectDisconnect), + sendMessageButton: document.getElementById(STRUCTURE.Chats.SendMessage), + messageBox: document.getElementById(STRUCTURE.Chats.MessageBox), + typingIndicator : document.getElementById(STRUCTURE.Chats.TypingIndicator), + totalUsers : document.getElementById(STRUCTURE.Info.TotalUsers) +}; + +export const { MessageBox: MessageBox,SendMessage } = STRUCTURE.Chats; +export const { remoteVideo, localVideo, muteVideoButton, muteAudioButton, chatBody, connectDisconnectButton, sendMessageButton, messageBox , typingIndicator ,totalUsers} = COMPONENT; + + + + + diff --git a/js/likes.js b/js/likes.js new file mode 100644 index 0000000..cf601ec --- /dev/null +++ b/js/likes.js @@ -0,0 +1,46 @@ +/************************************************* + * Not Refactered + * this is not the part of chat page + **************************************************/ + +const handelLikes = async (likes) => { + document.addEventListener('DOMContentLoaded', function () { + const tagInputField = document.querySelector('.tag-input-field'); + const tagsList = document.querySelector('.tags-list'); + if(!tagInputField || !tagsList){ + console.log("No tag input field found"); + return ; + } + tagInputField.addEventListener('keydown', function (event) { + const tagText = event.target.value.trim(); + + if (event.key === 'Enter' && tagText !== '') { + if (!likes.includes(tagText)) { + const tag = document.createElement('div'); + tag.className = 'tag'; + tag.innerHTML = ` + ${tagText} + × + `; + likes.push(tagText); + tagsList.appendChild(tag); + event.target.value = ''; + }else{ + alert("already exists"); + } + } + }); + + tagsList.addEventListener('click', function(event) { + if (event.target.classList.contains('tag-close-btn')) { + const tagText = event.target.previousElementSibling.textContent.trim(); + const index = likes.indexOf(tagText); + if (index !== -1) { + likes.splice(index, 1); + } + event.target.parentElement.remove(); + } + }); + }); +} +export default handelLikes; \ No newline at end of file diff --git a/js/main.js b/js/main.js new file mode 100644 index 0000000..904ac33 --- /dev/null +++ b/js/main.js @@ -0,0 +1,326 @@ +/************************************************* + * Refactered + * There is no commonets + **************************************************/ + +import { socket as Socket, getPartner, SendOffer, SendAnswer, SendCandidate, SendHangUP } from "./socket.js" +import { handelDataChannel } from "./chat.js" +import { updateWaitForPartner } from "./ui.js" +import { getStream, HandleRemoteStream } from "./stream.js"; +import handelLikes from "./likes.js"; +import { connectDisconnectButton as EscBtn, } from "./elements.js"; + +let partnerID; +let pc; +let dataChannel; +let localStream; +let socket; +let likes = []; +let partnerIntrests; +const configuration = { + iceServers: [ + { + urls: 'stun:stun.l.google.com:19302' + } + ] +} +// +var urlParams = new URLSearchParams(window.location.search); +var mode = urlParams.get('mode'); +var arrayParam = urlParams.get('tags'); +likes = JSON.parse(decodeURIComponent(arrayParam)); + +// WebRTC Functions +const StartCall = async (intrests) => { + socket = Socket; + socket.removeAllListeners(); + // Get the local stream + // try { + // localStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true }); + // } catch (e) { + // console.error("Error Getting User Media", e); + // alert("Please allow the camera and microphone access for video call access"); + // let check = confirm("If you continue with chat only mode, you will not be able to make video calls. Do you want to continue?"); + // if (!check) { + // return; + // } + // } + if (mode === "video") { + localStream = await getStream(); + if (!localStream) { + let check = confirm("If you continue with chat only mode, you will not be able to make video calls. Do you want to continue?"); + if (!check) { + return; + } + } + } + + + // let responce = await getPartner(intrests); + + // if(!responce){ + // console.log("No Partner Found, Please Try Again Later",responce); + // return; + // }else{ + // console.log("Partner Found",responce); + // } + getPartner(intrests).then((responce) => { + if (!responce) { + console.log("No Partner Found, Please Try Again Later", responce); + // EscBtn.disabled = false; + return; + } + else { + const WaitingPartner = (message, id) => { + if (!id) { + console.error("No Partner ID Found"); + return; + } + partnerIntrests = message?.intrests; + partnerID = id; + window.partnerID = id; + EscBtn.disabled = false; + InitaliseAnswerer(); + } + console.log("Partner Status:", responce); + let waitTimeout ; + if (responce.action === "intiate") { + partnerIntrests = responce.intrests; + partnerID = responce.partner_id; + window.partnerID = responce.partner_id; + EscBtn.disabled = false; + InitaliseOffer(); + } else { + const escMainText = document.getElementById("esc-main-text"); + escMainText.innerHTML = "Waiting..."; + EscBtn.disabled = true; + socket.on("handshake", WaitingPartner); + waitTimeout = setTimeout(() => { + socket.removeListener('handshake', WaitingPartner); + const escMainText = document.getElementById("esc-main-text"); + escMainText.innerHTML = "Matching not found, Click to retry..."; + EscBtn.disabled = false; + }, responce.time); + } + socket.onAny(()=>{ + if(waitTimeout){ + clearTimeout(waitTimeout); + } + }); + } + }); + // Update the UI + updateWaitForPartner("Waiting for partner"); + // Start Listening on handshake + // socket.on("handshake", (message, id) => { + // if (!id) { + // console.error("No Partner ID Found"); + // return; + // } + // console.log("Your Intrests", message?.intrests); + // partnerIntrests = message?.intrests; + // partnerID = id; + // window.partnerID = id; + + // EscBtn.disabled = false; + // // if the message is offer then start the call + // if (message.type == "offer") { + // //console.log("Offer Recieved") + // InitaliseOffer(); + // return true; + // } + + // else if (message.type == "answer") { + // //console.log("Answer Recieved") + // InitaliseAnswerer(); + // } + // }); + socket.on("hangup", () => { + //console.log("hangup receved"); + HangUp(); + }); +} +const InitaliseOffer = async () => { + pc = new RTCPeerConnection(configuration); + if (localStream) { + localStream.getTracks().forEach(track => pc.addTrack(track, localStream)); + } + handlePC(pc); + ListenForIceCandidate(socket, pc); + // only offer can create the data cahnnel + dataChannel = pc.createDataChannel("chat"); + handelDataChannel(dataChannel, partnerIntrests); + + // Offer Creation + const offer = await pc.createOffer(); + await pc.setLocalDescription(offer); + //console.log('Offer Created:', offer); + SendOffer(offer, partnerID); + + ListenForAnswer(socket, pc); +} +const InitaliseAnswerer = () => { + pc = new RTCPeerConnection(configuration); + if (localStream) { + localStream.getTracks().forEach(track => pc.addTrack(track, localStream)); + } + handlePC(pc); + // Answerer Will not create the data channel + ListenForIceCandidate(socket, pc); + ListenForOffer(socket, pc); +} + +const handlePC = (pc) => { + pc.onicecandidate = (e) => { + if (e.candidate) { + // console.log('New Ice Candidate:', JSON.stringify(e.candidate)); + SendCandidate(e.candidate, partnerID); + } + }; + + + // Handel Status + HandelStatus(pc); + + pc.ontrack = (e) => { + //console.log('New Track:', e.streams[0]); + HandleRemoteStream(e.streams[0]); + }; + pc.onnegotiationneeded = async () => { + console.log('Negotiation Needed'); + }; + pc.ondatachannel = (e) => { + //console.log('New Data Channel:', e.channel); + handelDataChannel(e.channel, partnerIntrests); + }; +} + +const HandelStatus = (pc) => { + + // webrtc status updaters + function updateState(stateName, newValue) { + try { + document.getElementById(stateName).textContent = newValue; + } catch (e) { + //console.log(e); + } + } + // Event listeners for state changes + pc.addEventListener('connectionstatechange', () => { + updateState('connection-state', pc.connectionState); + if (pc.connectionState === "connected") { + updateWaitForPartner(`Connected with parnter (${partnerID})`); + } + else if (pc.connectionState === "disconnected") { + updateWaitForPartner(`Disconnected with parnter (${partnerID})`); + partnerID = null; + HangUp(); + } + }); + pc.addEventListener('iceconnectionstatechange', () => { + updateState('ice-connection-state', pc.iceConnectionState); + }); + pc.addEventListener('icegatheringstatechange', () => { + updateState('ice-gathering-state', pc.iceGatheringState); + }); + pc.addEventListener('signalingstatechange', () => { + updateState('signaling-state', pc.signalingState); + }); + updateState('connection-state', pc.connectionState); + updateState('ice-connection-state', pc.iceConnectionState); + updateState('ice-gathering-state', pc.iceGatheringState); + updateState('signaling-state', pc.signalingState); +} + +//Socket Event Listening +const ListenForAnswer = (socket, pc) => { + socket.on("answer", async (answer) => { + try { + await pc.setRemoteDescription(answer); + } catch (error) { + console.error("Error setting remote description:", error); + } + }); + window.dataChannel = dataChannel; + window.pc = pc; + +} +const ListenForOffer = (socket, pc) => { + socket.on("offer", async (offer) => { + await pc.setRemoteDescription(offer); + const answer = await pc.createAnswer(); + await pc.setLocalDescription(answer); + SendAnswer(answer, partnerID); + window.pc = pc; + }); +} +const ListenForIceCandidate = (socket, pc) => { + socket.on("candidate", async (candidate) => { + try { + await pc.addIceCandidate(candidate); + } catch (e) { + console.error("Error Adding Ice Candidate", e); + } + }); +} + +const HangUp = () => { + console.log("Hangup Called"); + // if (startCallBtn) { + // startCallBtn.disabled = false; + // } + // handUpBtn.disabled = true; + + if (pc) { + pc.close(); + } + if (dataChannel) { + dataChannel.close(); + } + if (localStream) { + localStream.getTracks().forEach(track => track.stop()); + } + partnerID = null; + dataChannel = null; + localStream = null; + pc = null; + window.pc = null + socket = null; + // webrtc status updaters + function updateState(stateName, newValue) { + try { + document.getElementById(stateName).textContent = newValue; + } catch (e) { + // console.log(e); + } + } + updateState('connection-state', "------------"); + updateState('ice-connection-state', "------------"); + updateState('ice-gathering-state', "------------"); + updateState('signaling-state', "------------"); + // Waiting for partner Status + updateWaitForPartner("----------"); + +} +const SendHungUpFunction = () => { + try { + //console.log("Hangup Clicked"); + if (window.partnerID !== null) { + SendHangUP("bye", partnerID); + HangUp(); + //console.log("Hangup Sent"); + } + else { + console.log("No Partner ID Found"); + } + } + catch (e) { + // console.log(e); + } +} +if (handelLikes) { + handelLikes(likes); + window.likes = likes; +} + +export { StartCall, HangUp, SendHungUpFunction, likes, partnerID, Socket } diff --git a/js/socket.js b/js/socket.js new file mode 100644 index 0000000..44cf21c --- /dev/null +++ b/js/socket.js @@ -0,0 +1,123 @@ +/************************************************* + * Refactered + * There is no commonets + **************************************************/ + +let server = "http://localhost:3000"; +const socket = io(server); + +// socket.emit('offer', offer, id, (response) => { +// if (response.status === 'ok') { +// console.log('Offer Sent Successfully'); +// } else { +// console.error('Error Sending Offer'); +// } +// }); + + +const UpdateSocketStatus = (status) => { + const socketStatus = document.getElementById("socket-status"); + if (socketStatus) { + if (status == "Connected") { + socketStatus.textContent = `${status} to server , ID is:(${socket.id})`; + } + else { + socketStatus.textContent = `${status} to server`; + } + + } +}; +socket.on("connect", () => { + console.log("Connected to server"); + UpdateSocketStatus("Connected"); +}); +socket.on("disconnect", () => { + console.log("Disconnected from server"); + UpdateSocketStatus("Disconnected"); +}); +socket.on("reconnect", () => { + console.log("Reconnected to server"); + UpdateSocketStatus("Reconnected"); +}); +socket.on("error", (error) => { + console.error("Error:", error); + UpdateSocketStatus("Error"); +}); + + +const getPartner = (interests) => { + return new Promise((resolve, reject) => { + socket.emit('getPartner', interests, (response) => { + resolve(response); + }); + + // Handle timeout if acknowledgment is not received within 5 seconds + setTimeout(() => { + reject(new Error('Timeout: Acknowledgment not received within 5 seconds')); + }, 5000); + }); +}; +// Function to send 'candidate' event with acknowledgment and handle timeout +const SendCandidate = (candidate, id) => { + return new Promise((resolve, reject) => { + socket.emit('candidate', candidate, id, (response) => { + resolve(response); // Resolve with response from server + }); + + // Handle timeout if acknowledgment is not received within 1.5 seconds (1500ms) + setTimeout(() => { + reject(new Error('Timeout: Acknowledgment not received within 1500ms')); + }, 1500); + }); +}; + +// Function to send 'offer' event with acknowledgment and handle timeout +const SendOffer = (offer, id) => { + return new Promise((resolve, reject) => { + socket.emit('offer', offer, id, (response) => { + resolve(response); // Resolve with response from server + }); + + // Handle timeout if acknowledgment is not received within 1.5 seconds (1500ms) + setTimeout(() => { + reject(new Error('Timeout: Acknowledgment not received within 1500ms')); + }, 1500); + }); +}; + +// Function to send 'answer' event with acknowledgment and handle timeout +const SendAnswer = (answer, id) => { + return new Promise((resolve, reject) => { + socket.emit('answer', answer, id, (response) => { + resolve(response); // Resolve with response from server + }); + + // Handle timeout if acknowledgment is not received within 1.5 seconds (1500ms) + setTimeout(() => { + reject(new Error('Timeout: Acknowledgment not received within 1500ms')); + }, 1500); + }); +}; + +// Function to send 'hangup' event with acknowledgment and handle timeout +const SendHangUP = (message, id) => { + return new Promise((resolve, reject) => { + socket.emit('hangup', message, id, (response) => { + resolve(response); // Resolve with response from server + }); + + // Handle timeout if acknowledgment is not received within 1.5 seconds (1500ms) + setTimeout(() => { + reject(new Error('Timeout: Acknowledgment not received within 1500ms')); + }, 1500); + }); +}; + +export { + socket, + getPartner, + SendCandidate, + SendOffer, + SendAnswer, + SendHangUP +} \ No newline at end of file diff --git a/js/stream.js b/js/stream.js new file mode 100644 index 0000000..4f952c8 --- /dev/null +++ b/js/stream.js @@ -0,0 +1,96 @@ +/************************************************* + * + * Refacered Components if Components not found then there is no error + *************************************************/ + + +import {localVideo, remoteVideo,muteAudioButton,muteVideoButton} from "./elements.js"; + +const getStream = async () => { + let localStream; + const configuration = { + video: { + width: { exact: 320 }, + height: { exact: 240 }, + frameRate: { ideal: 30 }, + facingMode: 'user', // or 'user' for front-facing camera + aspectRatio: 4/3, // Example aspect ratio constraint + // Add more video constraints as needed + }, + audio: { + echoCancellation: true, + noiseSuppression: true, + autoGainControl: true, // Enable automatic gain control + sampleRate: { ideal: 48000 }, // Ideal sample rate (Hz) + channelCount: { ideal: 2 }, // Ideal number of audio channels (stereo) + latency: { max: 0.02 }, // Maximum acceptable latency (seconds) + // Add more audio constraints as needed + }, + }; + try{ + localStream = await navigator.mediaDevices.getUserMedia(configuration); + } catch (e) { + console.error("Error Getting User Media", e); + alert("Please allow the camera and microphone access for video call access"); + return null; + } + // const localVideo = localVideo; + let isAudioMuted = true; + let isVideoMuted = false; + + // Video Audio Mutting/Unmutting + if (localStream) { + localVideo?.style && (localVideo.style.transform = 'scaleX(-1)'); + // const muteAudioButton = document.getElementById("mute-audio"); + // const muteVideoButton = document.getElementById("mute-video"); + if (muteAudioButton) { + const audioTracks = localStream.getAudioTracks(); + audioTracks.forEach(track => { + track.enabled = false; + }); + muteAudioButton.addEventListener("click", () => { + + if (!localStream) return; + + + if (audioTracks.length === 0) return; + + isAudioMuted = !isAudioMuted; + audioTracks.forEach(track => { + track.enabled = !isAudioMuted; + }); + + muteAudioButton.innerHTML = isAudioMuted ? 'mic_off' : 'mic'; + }); + } + if (muteVideoButton) { + muteVideoButton.addEventListener("click", () => { + if (!localStream) return; + const videoTracks = localStream.getVideoTracks(); + if (videoTracks.length === 0) return; + isVideoMuted = !isVideoMuted; + videoTracks.forEach(track => { + track.enabled = !isVideoMuted; + }); + muteVideoButton.innerHTML = isVideoMuted ? 'videocam_off' : 'videocam'; + }); + } + } + // Local video stream + if (localVideo) { + localVideo.srcObject = localStream; + } + return localStream; +} +const HandleRemoteStream = (stream) => { + // const remoteVideo = document.getElementById("remote-video"); + if (remoteVideo) { + remoteVideo.style.transform = 'scaleX(-1)'; + remoteVideo.srcObject = stream; + remoteVideo.onloadedmetadata = () => { + remoteVideo.play(); + } + } +} + +export { getStream, HandleRemoteStream } \ No newline at end of file diff --git a/js/ui.js b/js/ui.js new file mode 100644 index 0000000..14e32d2 --- /dev/null +++ b/js/ui.js @@ -0,0 +1,87 @@ +/************************************************* + * Refactered + * There is no commonets + **************************************************/ + +import { chatBody,connectDisconnectButton as EscBtn ,totalUsers} from "./elements.js"; + +import { StartCall, SendHungUpFunction, likes, partnerID, Socket } from "./main.js"; + +const escMainText = document.getElementById("esc-main-text"); + +// Wait For Partner WEBRTC (For Testing Only) +const waitForPrtner = document.getElementById("wait-for-partner"); +const updateWaitForPartner = (status) => { + if (waitForPrtner) { + waitForPrtner.textContent = status; + } +} + +// How Many User Online UI (Depend on socket) +Socket.on("status", (state) => { + if (totalUsers) { + totalUsers.textContent = `${state.totalusers}00+ users`; + } + console.log("totol users"); +}); + +// Connection Close and Open UI (Start and End Call Depend On main.js) +let confirmExit = false; + +const EscapeHandel = () => { + if (partnerID) { + if (!confirmExit) { + confirmExit = true; + // escMainText.textContent = "Are you sure you want to leave the chat?"; + //escMainText.textContent = "आप चैट छोड़ना चाहते हैं क्या?"; + escMainText.textContent = "Really?"; + return; + } + //escMainText.textContent = "Leaving..."; + //escMainText.textContent = "छोड़ रहा है..."; + escMainText.textContent = "Connect"; + confirmExit = false; + SendHungUpFunction(); + return; + } + confirmExit = false; + escMainText.textContent = "Connecting"; + EscBtn.disabled = true; + if (chatBody) { + chatBody.innerHTML = ` +

Looking for someone you can chat with ...

+ + It may take a little while to find someone with common interests. If you get tired of + waiting, you can connect to a completely random stranger instead. + ` + } + StartCall(likes); +} + + +// SConnection Close and Open UI (Start and End Call Depend On main.js) with keyboard Intraction +if (EscBtn) { + EscBtn.addEventListener("click", EscapeHandel); +} +window.addEventListener("keydown", (e) => { + if (e.key === "Escape") { + EscapeHandel(); + } +}); + + +// Video Control API (Hide the video when textmode is opend) +const videoContainer = document.getElementById("video-containers"); +if (videoContainer) { + let urlParams = new URLSearchParams(window.location.search); + let mode = urlParams.get('mode'); + if (mode === "text") { + videoContainer.style.display = "none"; + } + else { + videoContainer.style.display = "block"; + } +} + + +export { updateWaitForPartner } \ No newline at end of file diff --git a/site.webmanifest b/site.webmanifest new file mode 100644 index 0000000..01b401e --- /dev/null +++ b/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "chat.heystranger.live", + "short_name": "heystranger.live", + "icons": [ + { + "src": "/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} \ No newline at end of file diff --git a/terms-condition.html b/terms-condition.html new file mode 100644 index 0000000..5a6fd16 --- /dev/null +++ b/terms-condition.html @@ -0,0 +1,348 @@ + + + + + + + Terms & Conditions + + + +

HeyStranger Terms of Service Agreement

+

Last Updated: 2022-10-06

+

IMPORTANT: PLEASE REVIEW THE ARBITRATION AGREEMENT AND CLASS ACTION WAIVER SET FORTH IN SECTION 9 BELOW + CAREFULLY, AS IT WILL REQUIRE YOU TO RESOLVE DISPUTES WITH HeyStranger ON AN INDIVIDUAL BASIS THROUGH FINAL AND + BINDING ARBITRATION. BY ENTERING INTO THIS AGREEMENT, YOU EXPRESSLY ACKNOWLEDGE THAT YOU HAVE READ AND + UNDERSTAND ALL OF THE TERMS OF THIS AGREEMENT AND HAVE TAKEN TIME TO CONSIDER THE CONSEQUENCES OF THIS IMPORTANT + DECISION.

+

1. Applicability and Acceptance of These Terms

+

This Terms of Service Agreement (“Agreement” or “Terms”) is a legal agreement + between you and HeyStranger.live, LLC (“HeyStranger”, “we”, or “us”). By + accessing or using the HeyStranger website, currently located at HeyStranger.live (the “Site”), or any + apps or other services offered or operated by HeyStranger (collectively, the “Services”), or by + checking a box or clicking a button signifying your acceptance of these Terms, you acknowledge that you have + read, understood and agree to be bound by these Terms. If you do not agree to these Terms, do not access or use + any of the Services.

+

When using the Services, you will be subject to HeyStranger’s Community Guidelines (“Community + Guidelines”) found here, and any additional guidelines, + policies or rules posted on the Services or otherwise made available or disclosed to you (collectively, the + “Rules”). All such guidelines, policies and rules are incorporated into these Terms by this + reference.

+

2. Use of the Services by Minors and Banned Persons

+

The Services are not available to, and shall not be accessed or used by, persons under the age of + 18. BY ACCESSING OR USING THE SERVICES, YOU REPRESENT AND WARRANT THAT YOU ARE AT LEAST 18 YEARS OF + AGE.

+

The Services are also not available to, and shall not be accessed or used by, any users previously blocked or + otherwise banned from accessing or using the Services.

+

3. Limited License to Use the Services

+

Subject to your compliance with these Terms and all other applicable Rules including but not limited to the + Community Guidelines, you are granted a limited, non-exclusive, non-sublicensable, revocable, non-transferable + license to access and use the Services solely for your personal and non-commercial use. No licenses or rights + are granted to you by implication or otherwise under any intellectual property rights owned or controlled by + HeyStranger or its licensors, except for licenses and rights expressly granted in these Terms. HeyStranger can terminate + this license as provided in Section 10 below.

+

You are solely responsible for compliance with any and all laws, rules, and regulations that may apply to your + use of the Services. You agree that you will comply with these Terms and the Community Guidelines and will not, + and will not assist or enable others to:

+ +

Neither the above restrictions, nor the Community Guidelines, the Rules, or anything else in the Terms, shall be + construed to create any rights enforceable by users, whether as third-party beneficiaries or otherwise. HeyStranger + has the right, but not the obligation, to enforce any of the foregoing.

+

4. User Content and Conduct; User Disputes

+

The Services provide communication channels designed to enable users to communicate with other users. HeyStranger does + not exert any control over the individuals you interact with, even if you select the “interest matching” chat + option or the college student chat option, which HeyStranger may offer. HeyStranger has no obligation to monitor these + communication channels but may, in its discretion, do so in connection with providing the Services. HeyStranger may + also terminate, suspend or ban your access to and use of the Services at any time, without notice, for any + reason in its sole discretion. You acknowledge and agree that any user content, including without limitation + text chats and video chats, is not created, endorsed or controlled by HeyStranger. HeyStranger will not under any + circumstances be liable for any user content or activity within the Services. HeyStranger is not responsible for + information or content that you choose to share within or through the Services nor is HeyStranger responsible for the + content or actions of other users of the Services. HeyStranger is not responsible for maintaining copies of any + information or communications you choose to submit to or through the Services.

+

You are solely responsible for your interaction with other users of the Services and other parties that you come + in contact with through the Services. To the fullest extent permitted by applicable law, HeyStranger hereby disclaims + any and all liability to you or any third party relating to your use of the Services. You acknowledge and agree + that HeyStranger does not have any special relationship with you as an end user, and as such, HeyStranger does not owe you + any duty to protect you from the acts of other users or other third parties.

+

Parental control protections (such as computer hardware, software, or filtering services) are commercially + available and may assist you in limiting minors’ access to materials that may be harmful to or inappropriate for + minors. There are a number of websites that provide information about such parental control protections, + including but not limited to https://www.connectsafely.org/controls/.

+

5. Intellectual Property Rights

+

The Services may, in their entirety or in part, be protected by copyright, trademark and/or other laws of the + United States and other countries. You acknowledge and agree that the Services, including all associated + intellectual property rights, are the exclusive property of HeyStranger and/or its licensors or authorizing third + parties. You will not remove, alter or obscure any copyright, trademark, service mark or other proprietary + rights notices incorporated in or accompanying the Services. All trademarks, service marks, logos, trade names, + trade dress and any other source identifiers of HeyStranger used on or in connection with the Services (collectively, + the “Marks”) are trademarks or registered trademarks of HeyStranger in the United States and abroad. + Trademarks, service marks, logos, trade names and any other proprietary designations of third parties used on or + in connection with the Services are used for identification purposes only and may be the property of their + respective owners. Use of any third-party trademark is intended only to identify the trademark owner and its + goods and services, and is not intended to imply any association between the trademark owner and HeyStranger.

+

6. Assumption of Risk and Disclaimer of Warranties

+

Assumption of Risk. You acknowledge and agree that use of the Services, including your + interactions with other users, may carry inherent risk and by accessing and using the Services, you choose to + assume those risks voluntarily. To the fullest extent permitted by applicable law, you assume full + responsibility for your use of the Services, including your interactions with other users.

+

TO THE FULLEST EXTENT PERMITTED UNDER APPLICABLE LAW, YOU KNOWINGLY, VOLUNTARILY AND FREELY ASSUME ALL RISKS, + BOTH KNOWN AND UNKNOWN, OF ACCESSING OR USING THE SERVICES, EVEN IF THOSE RISKS ARISE FROM THE NEGLIGENCE OR + CARELESSNESS OF HeyStranger, THIRD-PARTIES INCLUDING OTHER USERS OF THE SERVICES, OR DEFECTS IN THE SERVICES.

+

No Warranties. TO THE FULLEST EXTENT PERMITTED UNDER APPLICABLE LAW, HeyStranger PROVIDES THE + SERVICES ON AN “AS IS” AND “AS AVAILABLE” AND “WITH ALL FAULTS” BASIS, WITHOUT WARRANTY OF ANY KIND. TO THE + FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, HeyStranger AND ITS AFFILIATES AND LICENSORS DISCLAIM ALL WARRANTIES + AND CONDITIONS OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF TITLE, IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE (EVEN IF HeyStranger IS ADVISED OF + SUCH PURPOSE), AND IMPLIED WARRANTIES ARISING FROM A PARTICULAR COURSE OF DEALING OR USAGE OF TRADE. WITHOUT + LIMITING THE FOREGOING, NEITHER HeyStranger NOR ANY OF ITS AFFILIATES OR LICENSORS, NOR ANY OF ITS OR THEIR OFFICERS, + DIRECTORS, LICENSORS, EMPLOYEES OR REPRESENTATIVES REPRESENT OR WARRANT (I) THAT THE SERVICES WILL MEET YOUR + REQUIREMENTS OR BE ACCURATE, TRUTHFUL, COMPLETE, RELIABLE, OR ERROR FREE, (II) THAT THE SERVICES WILL ALWAYS BE + AVAILABLE OR WILL BE UNINTERRUPTED, ACCESSIBLE, TIMELY, RESPONSIVE, OR SECURE, (III) THAT ANY ERRORS OR DEFECTS + WILL BE CORRECTED, OR THAT THE SERVICES WILL BE FREE FROM VIRUSES, WORMS, TROJAN HORSES OR OTHER HARMFUL + PROPERTIES, (IV) THE ACCURACY, RELIABILITY, TIMELINESS OR COMPLETENESS OF ANY CONTENT AVAILABLE ON OR THROUGH + THE SERVICES, (V) ANY IMPLIED WARRANTY ARISING FROM COURSE OF DEALING OR USAGE OF TRADE, OR (VI) THAT ANY + CONTENT PROVIDED VIA THE SERVICES IS NON-INFRINGING. NO INFORMATION OR ADVICE PROVIDED THROUGH THE SERVICES BY + HeyStranger OR BY HeyStranger’S EMPLOYEES OR AGENTS SHALL CREATE ANY WARRANTY. Some jurisdictions do not allow the + exclusion of certain warranties, so some of the above limitations and exclusions may not apply to + you.

+

Other Users of the Services. HeyStranger HAS NO CONTROL OVER AND DOES NOT MAKE, AND HEREBY + EXPRESSLY DISCLAIMS, ANY REPRESENTATIONS, WARRANTIES OR GUARANTEES AS TO THE CONDUCT, ACTS OR OMISSIONS OF OTHER + USERS OF THE SERVICES. YOU ACKNOWLEDGE AND AGREE THAT YOU SHALL LOOK SOLELY TO THE OTHER USERS, AND NOT HeyStranger, + WITH RESPECT TO ANY CLAIMS OR CAUSES OF ACTION ARISING FROM OR RELATING TO THE ACTIONS OR CONDUCT OF OTHER USERS + OF THE SERVICES. TO THE FULLEST EXTENT PERMITTED UNDER APPLICABLE LAW, UNDER NO CIRCUMSTANCES SHALL HeyStranger BE + RESPONSIBLE FOR ANY LOSS, DAMAGE OR INJURY RESULTING FROM ANY ACTION, CONDUCT OR OMISSION OF ANY OTHER USER OF + THE SERVICES.

+

7. Limitation of Liability

+

Limitations on HeyStranger’s Liability. YOU ACKNOWLEDGE AND AGREE THAT, TO THE FULLEST EXTENT + PERMITTED BY LAW, THE ENTIRE RISK ARISING OUT OF YOUR ACCESS TO AND USE OF THE SERVICES REMAINS WITH YOU. + NEITHER HeyStranger NOR ANY OTHER PARTY INVOLVED IN CREATING, PRODUCING, OR DELIVERING THE SERVICES WILL BE LIABLE TO + YOU OR ANY THIRD PARTY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, PUNITIVE, EXEMPLARY OR CONSEQUENTIAL + DAMAGES, INCLUDING LOST PROFITS, LOSS OF DATA OR LOSS OF GOODWILL, SERVICE INTERRUPTION, COMPUTER DAMAGE OR + SYSTEM FAILURE OR THE COST OF SUBSTITUTE PRODUCTS OR SERVICES, OR FOR ANY DAMAGES FOR PERSONAL OR BODILY INJURY + OR EMOTIONAL DISTRESS ARISING OUT OF OR IN CONNECTION WITH (I) THESE TERMS, (II) THE USE OF THE SERVICES, + INCLUDING BUT NOT LIMITED TO ANY DAMAGE CAUSED BY ANY RELIANCE ON, OR ANY DELAYS, INACCURACIES, ERRORS OR + OMISSIONS IN, THE SERVICES, WHETHER PROVIDED BY HeyStranger OR BY THIRD PARTIES, (III) THE USE OF OR INABILITY TO USE + THE SERVICES FOR ANY REASON, OR (IV) YOUR COMMUNICATIONS, INTERACTIONS OR DEALINGS WITH, OR THE CONDUCT OF, + OTHER USERS OF THE SERVICES, WHETHER BASED ON WARRANTY, CONTRACT, TORT (INCLUDING NEGLIGENCE), PRODUCT LIABILITY + OR ANY OTHER LEGAL THEORY, AND WHETHER OR NOT HeyStranger HAS BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGE, EVEN + IF A LIMITED REMEDY SET FORTH HEREIN IS FOUND TO HAVE FAILED OF ITS ESSENTIAL PURPOSE.

+

IN NO EVENT WILL HeyStranger’S AGGREGATE LIABILITY ARISING OUT OF OR IN CONNECTION WITH THESE TERMS OR YOUR USE OF OR + INABILITY TO USE THE SERVICES (INCLUDING BUT NOT LIMITED TO YOUR INTERACTIONS WITH OTHER USERS OF THE SERVICES) + EXCEED ONE HUNDRED U.S. DOLLARS (U.S. $100.00).

+

The limitations of damages set forth above are fundamental elements of the basis of the bargain between HeyStranger + and you. Some jurisdictions do not allow the exclusion or limitation of liability for consequential or + incidental damages, so some of the above limitations and exclusions may not apply to you.

+

No Liability for Non-HeyStranger Actions. TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, + IN NO EVENT WILL HeyStranger BE LIABLE FOR ANY DAMAGES WHATSOEVER, WHETHER DIRECT, INDIRECT, GENERAL, SPECIAL, + COMPENSATORY, CONSEQUENTIAL, AND/OR INCIDENTAL, ARISING OUT OF OR RELATING TO THE CONDUCT, ACTS OR OMISSIONS OF + YOU OR ANY OTHER THIRD PARTY, INCLUDING OTHER USERS OF THE SERVICES, IN CONNECTION WITH THE USE OF THE SERVICES, + INCLUDING WITHOUT LIMITATION, BODILY INJURY, EMOTIONAL DISTRESS, AND/OR ANY OTHER DAMAGES. Some jurisdictions do + not allow the exclusion or limitation of liability for consequential or incidental damages, so some of the above + limitations and exclusions may not apply to you.

+

8. Indemnification

+

To the maximum extent permitted by applicable law, you agree to release, defend (at HeyStranger’s option), indemnify, + and hold HeyStranger and its affiliates and subsidiaries, and their officers, directors, employees and agents, + harmless from and against any claims, liabilities, damages, losses, and expenses, including without limitation, + reasonable attorney and accounting fees, arising out of or in any way connected with (i) your breach or alleged + breach of these Terms or any other applicable policies of HeyStranger (including but not limited to the Guidelines or + Rules), (ii) your use of the Services other than as authorized by these Terms, the Guidelines or Rules, (iii) + your interactions with other users of the Services, including without limitation any injuries, losses or damages + (whether compensatory, direct, incidental, consequential or otherwise) of any kind arising in connection with or + as a result of your interactions, (iv) any information or materials you submit through the Services, or (v) your + violation, or alleged violation, of any laws, regulations or third-party rights (all of the foregoing, + “Claims”). HeyStranger may assume exclusive control of any defense of any Claims (which shall not + excuse your obligation to indemnify HeyStranger), and you agree to fully cooperate with HeyStranger in such event. You + shall not settle any Claims without prior written consent from HeyStranger.

+

9. Dispute Resolution: Agreement to Arbitrate

+

Please read the following Section 9 carefully, as they affect your rights.

+

9.1 Agreement to Arbitrate and Timing of Claims

+

YOU AND HeyStranger MUTUALLY AGREE THAT ANY DISPUTE, CLAIM OR CONTROVERSY ARISING OUT OF OR RELATING IN ANY WAY TO + THESE TERMS OR THE APPLICABILITY, BREACH, TERMINATION, VALIDITY, ENFORCEMENT OR INTERPRETATION THEREOF OR TO THE + ACCESS TO AND USE OF THE SERVICES, WHETHER BASED IN CONTRACT, STATUTE, REGULATION, ORDINANCE, TORT (INCLUDING + WITHOUT LIMITATION, FRAUD, MISREPRESENTATION, FRAUDULENT INDUCEMENT, OR NEGLIGENCE), OR ANY OTHER LEGAL OR + EQUITABLE THEORY (COLLECTIVELY, “DISPUTE”) WILL BE SETTLED BY BINDING INDIVIDUAL ARBITRATION + (THE “ARBITRATION AGREEMENT”). ARBITRATION MEANS THAT THE DISPUTE WILL BE RESOLVED BY A NEUTRAL + ARBITRATOR INSTEAD OF IN A COURT BY A JUDGE OR JURY. THE ARBITRATOR WILL DECIDE ALL THRESHOLD QUESTIONS, + INCLUDING BUT NOT LIMITED TO ISSUES RELATING TO THE ENFORCEABILITY, REVOCABILITY, OR VALIDITY OF THIS + ARBITRATION AGREEMENT AND WHETHER EITHER PARTY LACKS STANDING TO ASSERT HIS/HER/ITS CLAIM(S).

+

YOU ACKNOWLEDGE AND AGREE THAT, REGARDLESS OF ANY STATUTE OR LAW TO THE CONTRARY, ANY CLAIM OR CAUSE OF ACTION + ARISING OUT OF OR RELATED TO THESE TERMS OR YOUR USE OF THE SERVICES MUST BE FILED WITHIN ONE (1) YEAR AFTER + SUCH CLAIM OR CAUSE OF ACTION AROSE OR BE FOREVER BARRED.

+

9.2 Exceptions to the Arbitration Agreement

+

Notwithstanding the Arbitration Agreement, you and HeyStranger each agree that (i) any dispute that may be brought in + small claims court may be instituted in a small claims court of competent jurisdiction, (ii) either you or + HeyStranger may seek injunctive relief in any court of competent jurisdiction to enjoin infringement or other misuse + of either party’s intellectual property rights (including without limitation, violation of any data use + restrictions contained in these Terms or other misuse of the Services) or based on other exigent circumstances + (e.g., imminent danger or commission of a crime, hacking, cyber-attack).

+

9.3 Pre-Arbitration Notification and Good Faith Negotiation

+

Prior to initiating an arbitration, you agree to provide HeyStranger with notice of the dispute, which notice shall + include a brief, written description of the dispute, the relief requested and your contact information. You must + send any such notice to HeyStranger by email at disputes@HeyStranger.live, with + “HeyStranger-Disputes” in the subject line, and by U.S. mail to HeyStranger.live, LLC, c/o Northwest Registered Agent LLC, + 7901 4th St. N., Suite 300, St. Petersburg, FL 33702. The parties agree to use their best efforts to resolve any + Dispute that is subject to the notification required under this section through informal negotiation, and good + faith negotiations shall be a condition to either party initiating a lawsuit or arbitration in accordance with + these Terms. If, after a good faith effort to negotiate, one of us feels the Dispute has not and cannot be + resolved informally, the party intending to pursue arbitration agrees to notify the other party via email prior + to initiating the arbitration.

+

9.4 The Arbitration

+

Except as provided herein, if we cannot resolve a Dispute by informal negotiation, any Dispute will be resolved + only by binding arbitration to be conducted by JAMS under its then current and applicable rules and procedures + (“JAMS Rules”), which are located at www.jamsadr.live, and + the rules set forth in these Terms. If there is a conflict between the JAMS Rules and the rules set forth in + these Terms, the rules set forth in these Terms will govern.

+

The arbitration will be conducted in English by a single arbitrator selected in accordance with JAMS Rules and + those rules will govern the payment of all filing, administration, and arbitrator fees unless this Arbitration + Agreement expressly provides otherwise. For U.S. residents, the arbitration shall be conducted in the U.S. state + in which you reside (subject to the ability of either party to appear at any in-person hearing by telephone or + other remote means, as provided below). For residents outside the United States, the arbitration shall be + conducted in Portland, Oregon. If the value of the relief sought is U.S. $25,000 or less, the arbitration will + be conducted based solely on written submissions; provided, however, that either party may request to have the + arbitration conducted by telephone or other remote means or in-person hearing, which request shall be subject to + the arbitrator’s discretion. Attendance at any in-person hearing may be made by telephone or other remote means + by you and/or us, unless the arbitrator requires otherwise after hearing from the parties on the issue. Keeping + in mind that arbitration is intended to be a fast and economical process, either party may file a dispositive + motion to narrow the issues or claims. Subject to the exclusions and waivers in these Terms, the arbitrator may + award any individual relief or individual remedies that are permitted by applicable law. The arbitrator’s award + shall be made in writing but need not provide a statement of reasons unless requested by a party or required + under applicable JAMS Rules. The arbitrator’s award shall be final and may be enforced in any court of competent + jurisdiction. Each party shall pay its own attorneys’ fees and costs unless there is an applicable statutory + provision requiring the prevailing party to be paid its attorneys’ fees and costs, in which case, a prevailing + party attorneys’ fees award shall be determined by applicable law.

+

The Federal Arbitration Act, applicable federal law, and the laws of the State of Oregon, without regard to + principles of conflict of laws, will govern any Dispute.

+

9.5 No Class Actions or Representative Proceedings

+

YOU AND HeyStranger ACKNOWLEDGE AND AGREE THAT TO THE FULLEST EXTENT PERMITTED BY LAW, WE ARE EACH WAIVING THE RIGHT + TO PARTICIPATE AS A PLAINTIFF OR CLASS MEMBER IN ANY PURPORTED CLASS ACTION LAWSUIT, CLASS-WIDE ARBITRATION, + PRIVATE ATTORNEY GENERAL ACTION, OR ANY OTHER REPRESENTATIVE PROCEEDING AS TO ALL DISPUTES. YOU AND HeyStranger AGREE + THAT THERE WILL BE NO CLASS ARBITRATION OR ARBITRATION IN WHICH AN INDIVIDUAL ATTEMPTS TO RESOLVE A DISPUTE AS A + REPRESENTATIVE OF ANOTHER INDIVIDUAL OR GROUP OF INDIVIDUALS. FURTHER, YOU AND HeyStranger AGREE THAT A DISPUTE + CANNOT BE BROUGHT AS A CLASS OR OTHER TYPE OF REPRESENTATIVE ACTION, WHETHER WITHIN OR OUTSIDE OF ARBITRATION, + OR ON BEHALF OF ANY OTHER INDIVIDUAL OR GROUP OF INDIVIDUALS.

+

If the class action waiver contained in this Section 9.5 is determined to be illegal or unenforceable, this + entire Arbitration Agreement will be unenforceable, and the Dispute will be decided by the courts in the state + of Oregon, Multnomah County, or the United States District Court for the Oregon, and the parties irrevocably + submit to the exclusive jurisdiction of such courts.

+

9.6 Jury Trial Waiver

+

YOU AND HeyStranger ACKNOWLEDGE AND AGREE THAT WE ARE EACH WAIVING THE RIGHT TO A TRIAL BY JURY AS TO ALL ARBITRABLE + DISPUTES AND AS TO ANY DISPUTE THAT PROCEEDS IN COURT RATHER THAN ARBITRATION AS PROVIDED HEREIN.

+

9.7 Severability

+

Except as provided in Section 9.5, in the event that any portion of this Arbitration Agreement is deemed illegal + or unenforceable, such provision shall be severed and the remainder of the Arbitration Agreement shall be given + full force and effect. If the arbitrator determines this Section 9 is unenforceable, invalid or has been revoked + as to any claim(s), then the Dispute as to such claim(s) will be decided by the courts in the state of Oregon, + Multnomah County, or the United States District Court for the Oregon, and the parties irrevocably submit to the + exclusive jurisdiction of such courts.

+

10. Term, Termination, and Survival

+

This Agreement will remain in full force and effect while you use the Services in accordance with these Terms and + any additional applicable Rules. HeyStranger may terminate this Agreement at any time without notice if we believe + that you have breached this Agreement or the Community Guidelines, including but not limited to, by using the + Services for non-personal use, engaging in prohibited activities, and any breach of your representations and + warranties. All provisions of this Agreement which by their nature should survive termination shall survive + termination, including without limitation, ownership provisions, warranty disclaimers, assumption of risk + agreement, release of claims, indemnity, limitations of liability, and dispute resolution.

+

11. General

+

11.1 Privacy Notice and Law Enforcement Inquiries

+

HeyStranger maintains a Privacy Policy describing the collection, retention, and use of information related to your + use of the Services. You can find the Privacy Policy, which is incorporated by reference into this Agreement, here.

+

HeyStranger’s obligations are subject to existing laws and legal process. Therefore, HeyStranger complies with valid legal + process (e.g., court order, search warrant, subpoena or similar legal process) issued in compliance with + applicable law from law enforcement agencies. Law enforcement may submit requests for information and legal + process to HeyStranger’s registered agent at the following address:

+
+

HeyStranger.live, LLC
+ c/o Northwest Registered Agent LLC
+ 7901 4th St. N., Suite 300
+ St. Petersburg, FL 33702

+
+

Law enforcement may also submit requests for information and legal process from an official government-issued + email address (e.g., name@agency.gov) to HeyStranger at lawenforcement@HeyStranger.live with “HeyStranger-LEO” in the subject line. + Non-law enforcement requests should not be submitted to this email address. HeyStranger will not respond to + correspondence sent by non-law enforcement officials to this email address. Please note that the + email address for law enforcement requests is provided for convenience only and does not waive any objections + HeyStranger may have, including the lack of jurisdiction or proper service.

+

11.2 Feedback

+

We welcome and encourage you to provide feedback, comments and suggestions for improvements to the Services + (collectively, “Feedback”). You may submit Feedback by emailing us at feedback@HeyStranger.live with “HeyStranger-Feedback” in the subject line. Any + Feedback you submit to us will be considered non-confidential and non-proprietary to you. By submitting Feedback + to us, you grant us a non-exclusive, worldwide, royalty-free, irrevocable, sub-licensable, perpetual license to + use and publish those ideas and materials for any purpose, without compensation to you.

+

11.3 Third-Party Links and Services

+

The Services may contain links to other websites, businesses, resources and advertisers, and other sites may link + to the Services. Clicking on a link will redirect you away from the Services to a third-party site or service. + HeyStranger is not responsible for examining or evaluating, and does not warrant the goods, services or offerings of + any third party or the content of their websites or advertisements. Consequently, HeyStranger does not assume any + liability or responsibility for the accuracy, actions, products, services, practices, availability or content of + such third parties. You should direct any concerns regarding other sites and services to their operators.

+

11.4 Assignment

+

You may not assign, transfer or delegate this Agreement and your rights and obligations hereunder without + HeyStranger’s prior written consent. HeyStranger may, without restriction, assign, transfer or delegate this Agreement and + any rights and obligations hereunder, at its sole discretion.

+

11.5 Changes to the Services or the Terms

+

HeyStranger reserves the right, at any time and in our sole discretion, to amend, modify, suspend, or terminate, + temporarily or permanently, the Services, and any part thereof, without notice to you. HeyStranger shall have no + liability to you or any other person or entity for any modification, suspension, or termination of the Services + or any part thereof.

+

HeyStranger reserves the right to modify these Terms (effective on a prospective basis) at any time in accordance with + this provision. Therefore, you should review these Terms regularly. If we make changes to these Terms, we will + post the revised Terms on the Services and update the “Last Updated” date at the top of these Terms. If you do + not terminate this Agreement before the date the revised Terms become effective, your continued access to or use + of the Services will constitute acceptance of the revised Terms.

+

Special terms or rules may apply to some Services. Any such terms are in addition to these Terms. In the event of + any conflict or inconsistency between these Terms, our Privacy Notice, and any rules, restrictions, limitations, + terms and/or conditions that may be communicated to users of the Services, HeyStranger shall determine which rules, + restrictions, limitations, terms and/or conditions shall control and prevail, in our sole discretion, and you + specifically waive any right to challenge or dispute such determination.

+

11.6 No Third-Party Beneficiaries

+

This Agreement does not, and is not intended to, confer any rights or remedies upon any person other than the + parties hereto.

+

11.7 No Waiver and Severability

+

HeyStranger’s failure to enforce a provision of this Agreement is not a waiver of its right to do so later or to + enforce any other provision. Except as expressly set forth in this Agreement, the exercise by either party of + any of its remedies under this Agreement will be without prejudice to its other remedies under this Agreement or + otherwise permitted under law.

+

Except as explicitly provided herein, if any provision of this Agreement is held to be unenforceable for any + reason, such provision will be reformed only to the extent necessary to make it enforceable, and such decision + will not affect the enforceability of such provision under other circumstances, or of the remaining provisions + hereof under all circumstances.

+

11.8 Governing Law and Venue

+

These Terms will be interpreted in accordance with the laws of the State of Oregon and the United States of + America, without regard to conflict-of-law provisions. Judicial proceedings (other than small claims + proceedings) that are excluded from the Arbitration Agreement in Section 9 must be brought in the state or + federal courts located in Portland, Oregon unless we both agree to some other location. You and we both consent + to venue and personal jurisdiction in Portland, Oregon.

+

11.9 Entire Agreement

+

Except as it may be supplemented by additional terms and conditions, policies, guidelines or standards as + provided herein, this Agreement constitutes the entire agreement between HeyStranger and you pertaining to the + subject matter hereof, and supersedes any and all prior oral or written understandings or agreements between + HeyStranger and you in relation to the access to and use of the Services.

+ + + \ No newline at end of file diff --git a/test.html b/test.html new file mode 100644 index 0000000..52004d8 --- /dev/null +++ b/test.html @@ -0,0 +1,116 @@ + + + + + + Video Calling App + + + +
+ + +
+ + + +
+
+ + + diff --git a/test2.html b/test2.html new file mode 100644 index 0000000..31a18b8 --- /dev/null +++ b/test2.html @@ -0,0 +1,145 @@ + + + + + + Video Call with Chat + + + +
+

John Doe

+
+ + + +
+
+
+
+ + +
+
+ + + +
+
+ + + + diff --git a/test4.html b/test4.html new file mode 100644 index 0000000..8b6e314 --- /dev/null +++ b/test4.html @@ -0,0 +1,147 @@ + + + + + + + HeyStranger.live | Stranger Video Calling App + + + + + + +
+
+ + + +
+
+
+
+
+ +
+ +
+
+ +
+ + + + +
+ + +
+
+ +
+
+
+ +
+
+
+
Click On Left Button or ESC Button to connect.
+
+
+
Click to connect
+ +
+   +
+
+
+ + + +
+
+
+
+
+
+
+ + + + + + + + + + \ No newline at end of file