sp-hydra-veil-gui/SMS-Exchange-Linux-GUI/GUI.py
2026-01-28 13:15:44 +01:00

2467 lines
111 KiB
Python
Executable file

# Loading and using the config
from local_data_operations.search_or_setup_json import search_key_in_json
from local_data_operations.load_or_setup_config import load_or_setup_config, replace_config_value, setup_path_to_dump_initial_api_data, load_or_setup_local_api_data_folder
from local_data_operations.local_logs import get_profile_location_and_proxy_status_as_tuple, create_or_add_to_profile_config, return_all_locally_saved_orders_for_the_current_profile, delete_an_order, setup_email_config, get_email_data, wipe_email_data, wipe_location_and_proxy, wipe_entire_profile_data
# generate buyer id:
from local_data_operations.generate_random_number_string import generate_random_number_string
# manipulating data from the API:
from process_api_data.extract_a_list_of_values import extract_a_list_of_values, get_the_locations_for_a_service
from process_api_data.read_from_text_file_into_list import read_from_text_file_into_list
from process_api_data.convert_to_dictonary import search_by_category
# manipulating email data to send or recieve from the API:
from api_interaction.get_initial_email_data import get_initial_email_data
from process_email_data.filter_email_names import filter_email_names
from process_email_data.load_email_operators import load_email_operators
# coordinating with API:
from api_interaction.send_data_to_flask import send_data_to_flask, dispute_send_data_to_flask, check_if_paid_by_sending_data_to_flask, ready_for_code_by_sending_data_to_flask, send_crypto_address_for_refund, restore_an_already_finalized_number
from api_interaction.get_and_save_json_from_our_api import get_and_save_json_from_our_api
from api_interaction.should_api_be_triggered import should_api_be_triggered
# process the proxy:
from interact_with_rest_of_app.process_the_proxy import process_the_proxy
# Generic imports:
# async:
import aiohttp
from aiohttp import ClientConnectorError, ClientResponseError
import asyncio
# basic tools:
import os
import sys
import json
# error log, which line:
import traceback
# GUI visual:
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QComboBox, QPushButton, QSizePolicy, QMessageBox, QListWidget, QGridLayout, QHBoxLayout, QComboBox, QMainWindow, QInputDialog, QLineEdit
from qasync import QEventLoop, asyncSlot
from PyQt6.QtCore import QCoreApplication, QTimer
# FOR DEBUG UNCOMMENT, if I want to start tracing memory allocations
import tracemalloc
tracemalloc.start()
class BuyerPeerPeerGUI(QWidget):
def __init__(self):
super().__init__()
# Name of the config file for entire app:
self.name_of_config_file = "sms_config.json"
# Load Config data for entire rest of the app to be searched with the 'search_key_in_json' function:
self.config_file_data = load_or_setup_config(self.name_of_config_file)
# for api data:
self.folder_for_api_data = load_or_setup_local_api_data_folder()
self.email_file_path = f"{self.folder_for_api_data}/email_operators.json"
self.filename_for_locations_data = f"{self.folder_for_api_data}/services_by_type_and_location.json"
# Commented out format to search config:
# result = search_key_in_json(config_raw_data, "key", default)
# setup error logs:
self.error_log_file_path = search_key_in_json(
self.config_file_data, "error_log_file_path", "error_log_for_gui.txt")
self.setWindowTitle("SMS Exchange | HydraVeil")
self.setFixedSize(800, 600)
self.move(100, 100)
# Set the overall style
self.setStyleSheet("background-color: black; color: white;")
# set styles for entire project:
self.active_style_box = """
background-color: #282828; /* Dark background for contrast */
color: #FFD700; /* Gold color for text */
font-size: 30px;
font-family: 'Press Start 2P', cursive; /* Retro font */
border: 3px solid #00FF00; /* Bright green border */
padding: 15px; /* Increased padding */
text-align: center; /* Centering text */
"""
self.lowkey_style_box = """
background-color: #444444; /* Darker grey for a muted effect */
color: #A9A9A9; /* Light grey for text */
font-size: 30px;
font-family: 'Press Start 2P', cursive; /* Keeping the retro font */
border: none; /* No border */
padding: 15px; /* Maintained padding */
text-align: center; /* Centering text */
"""
self.blue_chill_style = """
QPushButton {
font-size: 30px;
font-weight: normal;
color: #007BFF; /* Bright blue text */
background-color: transparent; /* No background */
border: 2px solid #007BFF; /* Blue border */
border-radius: 5px; /* Slightly rounded corners */
padding: 10px 15px; /* Vertical and horizontal padding */
}
QPushButton:hover {
background-color: rgba(0, 123, 255, 0.1); /* Light blue background on hover */
}
QPushButton:pressed {
background-color: rgba(0, 123, 255, 0.2); /* Darker blue when pressed */
}
"""
# Create layout
self.layout = QVBoxLayout()
# This label style is used in many spots throughout the various pages:
self.label_style = "font-size: 40px; color: white;"
# Set layout to the main window:
self.setLayout(self.layout)
# Display to the end-user that it's fetching data, although technically it didn't start doing it yet:
self.label_for_api_fetch = QLabel(f"Fetching Available Services")
self.label_for_api_fetch.setStyleSheet(self.label_style)
self.label_for_api_fetch.setSizePolicy(
# Expanding vertical size policy
QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
self.layout.addWidget(self.label_for_api_fetch)
# We don't want the GUI to not load until after the API call is done, so we schedule an async function to run after the GUI is shown,
QTimer.singleShot(0, self.step_1_run_api_async)
# Set layout to the main window
self.setLayout(self.layout)
# Start basic functions section:
def show_error_message(self, message):
msg_box = QMessageBox(self)
msg_box.setIcon(QMessageBox.Icon.Warning)
msg_box.setText(message)
msg_box.setWindowTitle('Error')
msg_box.exec()
def log_an_error(self, error):
with open(self.error_log_file_path, 'a') as file:
file.write(f'{error}\n')
# End basic functions section
# We're getting the data from an API, and displaying either the data in lists, or an error message of why it failed to get the data,
@asyncSlot()
async def step_1_run_api_async(self):
period_of_time = 3600 # an hour
# does the user want to use existing data or new data?
are_we_doing_an_api_call = should_api_be_triggered(
self.filename_for_locations_data, period_of_time)
if are_we_doing_an_api_call == False:
# we need to do an API call to get fresh data:
await self.step_2_actually_fetch_data_from_api()
else:
# do NOT do the API call, skip to using the existing local data:
self.after_fetched_data_from_api_is_done()
async def step_2_actually_fetch_data_from_api(self):
non_binary_of_did_it_get_it_from_api_or_not = await get_and_save_json_from_our_api(self.filename_for_locations_data)
if non_binary_of_did_it_get_it_from_api_or_not == "worked":
self.label_for_api_fetch.setText("Fetching Email Operators")
next_get_email_data = await get_initial_email_data(self.email_file_path)
if next_get_email_data == "worked":
self.after_fetched_data_from_api_is_done()
else:
self.display_error_message_from_failed_connection(
next_get_email_data)
else:
self.display_error_message_from_failed_connection(
non_binary_of_did_it_get_it_from_api_or_not)
def display_error_message_from_failed_connection(self, error_message_content):
# Format the Label for a long message, and Display the Error of why it failed to get the data:
self.label_for_api_fetch.setStyleSheet("font-size: 40px;")
self.label_for_api_fetch.setWordWrap(True)
self.label_for_api_fetch.setFixedWidth(800)
self.label_for_api_fetch.setText(str(error_message_content))
def after_fetched_data_from_api_is_done(self):
try:
# Check if the label exists and is not already hidden
if self.label_for_api_fetch is not None:
if not self.label_for_api_fetch.isHidden():
self.label_for_api_fetch.hide()
else:
pass
except Exception as e:
pass
# self.show_error_message(f"An unexpected error occurred: {e}")
# self.log_an_error(e)
# Generate ID:
self.peer_to_peer_billing_id = generate_random_number_string()
# Display the ID (with that label style declared in the init section):
label_for_peer_to_peer_billing_id = QLabel(
f"Your P2P ID is: {self.peer_to_peer_billing_id}")
label_for_peer_to_peer_billing_id.setStyleSheet(self.label_style)
label_for_peer_to_peer_billing_id.setSizePolicy(
# Expanding vertical size policy
QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
self.layout.addWidget(label_for_peer_to_peer_billing_id)
# Create a horizontal layout for the two QListWidgets
self.top_ribbon_h_layout = QHBoxLayout()
# Add the left column's label, above box:
self.left_label_above_box = QLabel("General Categories")
smaller_sub_label_style = "font-size: 30px; color: grey;"
self.left_label_above_box.setStyleSheet(smaller_sub_label_style)
# Add the right column's label, above box:
self.right_label_above_box = QLabel("Specific Sites")
self.right_label_above_box.setStyleSheet(smaller_sub_label_style)
self.top_ribbon_h_layout.addWidget(self.left_label_above_box)
self.top_ribbon_h_layout.addWidget(self.right_label_above_box)
self.layout.addLayout(self.top_ribbon_h_layout)
# Create a horizontal layout for the two QListWidgets
self.h_layout = QHBoxLayout()
# The initial API call saved the initial data JSON to this path:
with open(self.filename_for_locations_data, 'r') as file:
self.initial_data = json.load(file)
# Each category on the left, gets the filtered values of the data on the right
self.social_list = extract_a_list_of_values(
self.initial_data, "social")
self.big_tech_list = extract_a_list_of_values(
self.initial_data, "big_tech")
self.business_list = extract_a_list_of_values(
self.initial_data, "business")
self.travel_list = extract_a_list_of_values(
self.initial_data, "travel")
self.AI_list = extract_a_list_of_values(self.initial_data, "AI")
# Mapping of items to their corresponding lists
self.list_mapping = {
'social_media': self.social_list,
'big_tech': self.big_tech_list,
'business': self.business_list,
'travel': self.travel_list,
'AI': self.AI_list
}
# This is the left category column:
self.list_widget1 = QListWidget()
# Add items to list_widget1
self.list_widget1.addItems(self.list_mapping.keys())
self.list_widget1.setSelectionMode(
QListWidget.SelectionMode.SingleSelection)
self.list_widget1.setStyleSheet(
"background-color: grey; color: white; font-size: 26px;")
# Create the second QListWidget
self.list_widget2 = QListWidget()
self.list_widget2.setSelectionMode(
QListWidget.SelectionMode.SingleSelection)
self.list_widget2.setStyleSheet(
"background-color: grey; color: white; font-size: 26px;")
# Add the QListWidgets to the horizontal layout
self.h_layout.addWidget(self.list_widget1)
self.h_layout.addWidget(self.list_widget2)
# Set the QListWidget style with larger font size
self.list_widget1.setStyleSheet(
# Adjust font size as needed
"background-color: grey; color: white; font-size: 26px;")
self.list_widget2.setStyleSheet(
# Adjust font size as needed
"background-color: grey; color: white; font-size: 26px;")
# Connect the item selection change signal to the update method
self.list_widget1.itemClicked.connect(self.on_item_clicked)
self.list_widget2.itemClicked.connect(self.on_right_item_clicked)
# Create dropdown menus:
self.payment_method_dropdown = QComboBox()
self.location_dropdown = QComboBox()
self.email_dropdown = QComboBox()
# Populate dropdowns with defaults:
# Start Cryptocurrency dropdown section:
default_currency = search_key_in_json(
self.config_file_data, "default_currency", False)
if default_currency == False:
payment_methods_list = [
'Monero', "Bitcoin_Lightning", "Litecoin", "Bitcoin"]
else:
payment_methods_list = [default_currency]
self.payment_method_dropdown.addItems(payment_methods_list)
# End Cryptocurrency dropdown section
# Setup Location dropdown:
locations_list = ["Pick a Location"]
self.location_dropdown.addItems(locations_list)
# end Locations dropdown
# Start EMAIL dropdown section:
# do we already have email data?
packed_email_data = get_email_data() # calls function from local_logs.py
# if we do NOT yet have an email:
if packed_email_data == False or packed_email_data == "error":
self.turn_off_email_option = search_key_in_json(
self.config_file_data, "turn_off_email_option", False)
# did the user disable email in the options?
if self.turn_off_email_option == False:
email_operators_list = load_email_operators(
self.email_file_path)
else:
email_operators_list = ["email disabled"]
# else we already have an email for this profile:
else:
email_operators_list = ["profile already has an email"]
if email_operators_list is None:
empty_list = ["random"]
self.email_dropdown.addItems(empty_list)
else:
self.email_dropdown.addItems(email_operators_list)
# end Email dropdown
# Set text color and font size for dropdowns:
self.payment_method_dropdown.setStyleSheet(
"color: white; background-color: green; font-size: 24px;")
self.location_dropdown.setStyleSheet(
"color: white; background-color: red; font-size: 24px;")
self.email_dropdown.setStyleSheet(
"color: black; background-color: white; font-size: 20px;")
# display the profile status once they select a service:
self.label_for_profile_status = QLabel(f"Profile Status")
self.label_for_profile_status.setStyleSheet(
"font-size: 15px; color: white;")
self.label_for_profile_status.setWordWrap(True)
self.label_for_profile_status.setSizePolicy(
QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
# for now hide it. But later, this will appear after they select a service,
self.label_for_profile_status.setVisible(False)
# Create a button to show selected items
self.button = QPushButton("Residential Proxy, SMS, and Email! (€11)")
# Set background and text color self.button.clicked.connect(self.show_selected)
self.button.setStyleSheet(
"font-size: 30px; padding: 15px; background-color: green; color: yellow;")
self.button.clicked.connect(self.on_button_click)
# Button to clear selections
self.just_sms_button = QPushButton("SMS Only (€5)")
# self.just_sms_button.setStyleSheet("font-size: 20px; padding: 15px; background-color: grey; color: black;") # Set background and text color self.button.clicked.connect(self.show_selected)
self.just_sms_button.setStyleSheet("""
QPushButton {
font-size: 20px;
font-weight: bold;
color: #218838; /* dark green text */
background-color: #ffd700; /* Gold background */
border: 2px solid #ffcc00; /* Light gold border */
border-radius: 25px; /* Rounded corners */
padding: 15px 30px; /* Generous padding */
text-align: center; /* Center the text */
}
QPushButton:hover {
background-color: #f0c36d; /* Lighter gold on hover */
border-color: #ffdb58; /* Change border color on hover */
}
QPushButton:pressed {
background-color: #c8a23b; /* Darker gold when pressed */
border-color: #b89a26; /* Darker border when pressed */
}
""")
self.just_sms_button.clicked.connect(self.just_sms_no_proxy)
# Create a button for more options, including to allow the previous sessions to be restored:
self.more_options_button = QPushButton("More Options")
# self.more_options_button.setStyleSheet("font-size: 15px; padding: 10px; background-color: grey; color: black;") # Set background and text color self.button.clicked.connect(self.show_selected)
self.more_options_button.clicked.connect(
self.update_ui_to_display_more_options)
self.more_options_button.setStyleSheet(self.blue_chill_style)
# Add widgets to layout:
self.layout.addLayout(self.h_layout)
self.layout.addWidget(self.payment_method_dropdown)
self.layout.addWidget(self.location_dropdown)
self.layout.addWidget(self.email_dropdown)
self.layout.addWidget(self.label_for_profile_status)
self.layout.addWidget(self.button)
self.layout.addWidget(self.just_sms_button)
# but hide the send button till they fill in the fields:
self.button.setVisible(False)
self.just_sms_button.setVisible(False)
self.layout.addWidget(self.more_options_button)
self.service_literally_clicked_already = "no"
# Start: Display More Options Menu:
def update_ui_to_display_more_options(self):
try:
# Clear all widgets from the vertical layout
for i in reversed(range(self.layout.count())):
item = self.layout.itemAt(i)
if item is not None:
widget = item.widget()
if widget is not None:
widget.deleteLater()
# Clear all widgets from the horizontal layout
for i in reversed(range(self.h_layout.count())):
item = self.h_layout.itemAt(i)
if item is not None:
widget = item.widget()
if widget is not None:
widget.deleteLater()
for i in reversed(range(self.top_ribbon_h_layout.count())):
item = self.top_ribbon_h_layout.itemAt(i)
if item is not None:
widget = item.widget()
if widget is not None:
widget.deleteLater()
except:
pass
finally:
# Get Locally Saved Profile Data:
profile_location_and_proxy_tuple = get_profile_location_and_proxy_status_as_tuple()
# Find out if it's a Pre-existing Profile. It's possible the person went to the menu before selecting a service
if profile_location_and_proxy_tuple == False:
profile_menu_data = "Brand New Profile.\nNo Location Yet."
else:
# Pre-existing profiles have a location already,:
profile_location, profile_proxy_status = profile_location_and_proxy_tuple
profile_menu_data = f"Profile Location: {profile_location}"
# Options Menu Profile Display
self.options_menu_label = QLabel(f"Menu\n{profile_menu_data}")
self.options_menu_label.setStyleSheet(self.active_style_box)
self.options_menu_label.setWordWrap(True)
self.layout.addWidget(self.options_menu_label)
# restore previous interrupted session button:
self.restore_previous_button = QPushButton(
"Restore a Previous Session")
self.restore_previous_button.setStyleSheet(
"font-size: 40px; padding: 10px; background-color: green; color: yellow;")
self.restore_previous_button.clicked.connect(
self.restore_previous_session)
self.layout.addWidget(self.restore_previous_button)
# email options button:
self.get_only_an_email_button = QPushButton("Email Options")
self.get_only_an_email_button.setStyleSheet(
"font-size: 30px; padding: 10px; background-color: red; color: blue;")
self.get_only_an_email_button.clicked.connect(
self.email_options_ui)
self.layout.addWidget(self.get_only_an_email_button)
# proxy info button:
self.proxy_options_button = QPushButton(
"Proxy and Profile Options")
self.proxy_options_button.setStyleSheet(
"font-size: 30px; padding: 10px; background-color: black; color: white;")
self.proxy_options_button.clicked.connect(
self.update_ui_for_proxy_data)
self.layout.addWidget(self.proxy_options_button)
# disable local logs button:
self.disable_local_logs_button = QPushButton("SMS Preferences")
self.disable_local_logs_button.setStyleSheet(
"font-size: 30px; padding: 10px; background-color: white; color: black;")
self.disable_local_logs_button.clicked.connect(
self.update_ui_to_change_local_logs)
self.layout.addWidget(self.disable_local_logs_button)
# change default cryptocurrency button:
self.change_default_currency_button = QPushButton(
"Change Default Cryptocurrency")
self.change_default_currency_button.setStyleSheet(
self.blue_chill_style)
self.change_default_currency_button.clicked.connect(
self.update_ui_to_change_default_currency)
self.layout.addWidget(self.change_default_currency_button)
# frequency button:
# self.connection_frequency_button = QPushButton("Connection Frequency")
# self.connection_frequency_button.setStyleSheet("font-size: 30px; padding: 10px; background-color: white; color: black;")
# self.connection_frequency_button.clicked.connect(self.update_ui_to_change_local_logs)
# self.layout.addWidget(self.connection_frequency_button)
# return to main page button:
self.return_to_the_main_page_button = QPushButton(
"Return to the Main Page")
self.return_to_the_main_page_button.setStyleSheet(
"font-size: 30px; padding: 10px; background-color: green; color: yellow;")
self.return_to_the_main_page_button.clicked.connect(
self.update_ui_to_return_to_the_main_page)
self.layout.addWidget(self.return_to_the_main_page_button)
def update_ui_for_proxy_data(self):
self.clear_the_main_page_ui()
# Options Menu Profile Display
self.options_menu_label = QLabel(f"Proxy Menu")
self.options_menu_label.setStyleSheet(self.active_style_box)
self.options_menu_label.setWordWrap(True)
self.layout.addWidget(self.options_menu_label)
# Get Locally Saved Profile Data:
profile_location_and_proxy_tuple = get_profile_location_and_proxy_status_as_tuple()
# Find out if it's a Pre-existing Profile. It's possible the person went to the menu before selecting a service
if profile_location_and_proxy_tuple == False:
profile_menu_data = "This Profile does not have a Location Yet."
else:
# Pre-existing profiles have a location already,:
profile_location, profile_proxy_status = profile_location_and_proxy_tuple
profile_menu_data = f"Profile Location: {profile_location}"
# proxy data wipe button:
self.proxy_wipe_button = QPushButton("Delete Proxy Only")
self.proxy_wipe_button.setStyleSheet(
"font-size: 30px; padding: 10px; background-color: red; color: white;")
self.proxy_wipe_button.clicked.connect(self.wipe_email_data_in_gui)
self.layout.addWidget(self.proxy_wipe_button)
# proxy data wipe button:
self.wipe_entire_profile_button = QPushButton(
"Wipe entire Profile")
self.wipe_entire_profile_button.setStyleSheet(
"font-size: 30px; padding: 10px; background-color: red; color: black;")
self.wipe_entire_profile_button.clicked.connect(
self.wipe_entire_profile_in_gui)
self.layout.addWidget(self.wipe_entire_profile_button)
self.options_menu_label.setText(f"{profile_menu_data}")
# return to main page button:
self.return_to_the_main_page_button = QPushButton(
"Return to the Main Page")
self.return_to_the_main_page_button.setStyleSheet(
"font-size: 30px; padding: 10px; background-color: green; color: yellow;")
self.return_to_the_main_page_button.clicked.connect(
self.update_ui_to_return_to_the_main_page)
self.layout.addWidget(self.return_to_the_main_page_button)
def wipe_entire_profile_in_gui(self):
# Create a message box with warning icon
msg_box = QMessageBox()
msg_box.setIcon(QMessageBox.Icon.Warning)
msg_box.setText(
"Are you sure you want to delete your proxy and SMS data?")
msg_box.setWindowTitle("Confirmation")
# delete/cancel buttons
delete_button = msg_box.addButton(
"Delete", QMessageBox.ButtonRole.AcceptRole)
msg_box.addButton("Cancel", QMessageBox.ButtonRole.RejectRole)
msg_box.exec()
# Determine which button was pressed
if msg_box.clickedButton() == delete_button:
print("delete")
did_it_wipe = wipe_entire_profile_data()
if did_it_wipe == True:
self.options_menu_label.setText("Blank Location")
else:
self.options_menu_label.setText(
"Error! Profile wipe failed, please do it manually.")
else:
pass # Do nothing on Cancel
def wipe_email_data_in_gui(self):
# call the function from local_logs module. (it returns true if deletes it OR also true if it doesn't exist)
did_it_wipe = wipe_location_and_proxy()
if did_it_wipe == True:
self.update_ui_to_return_to_the_main_page()
else:
self.options_menu_label.setText(
"Error! Failed to Wipe Location Data")
def update_ui_to_return_to_the_main_page(self):
try:
# Call the method to remove the grid layout
self.remove_grid_layout()
except:
pass
try:
# Clear all widgets from the vertical layout
for i in reversed(range(self.layout.count())):
item = self.layout.itemAt(i)
if item is not None:
widget = item.widget()
if widget is not None:
widget.deleteLater()
except:
pass
finally:
self.after_fetched_data_from_api_is_done()
def clear_the_main_page_ui(self):
try:
# Clear all widgets from the vertical layout
for i in reversed(range(self.layout.count())):
item = self.layout.itemAt(i)
if item is not None:
widget = item.widget()
if widget is not None:
widget.deleteLater()
except:
pass
def update_ui_to_change_default_currency(self):
self.clear_the_main_page_ui()
# Label to display the email:
self.instructions_for_currency = QLabel(
f"Select From the Dropdown Below:")
self.instructions_for_currency.setStyleSheet(self.active_style_box)
self.instructions_for_currency.setWordWrap(True)
self.layout.addWidget(self.instructions_for_currency)
self.payment_method_dropdown = QComboBox()
self.payment_method_dropdown.setStyleSheet(
"color: white; background-color: green; font-size: 50px;")
payment_methods_list = [
'Monero', "Bitcoin_Lightning", "Litecoin", "Bitcoin"]
self.payment_method_dropdown.clear()
self.payment_method_dropdown.addItems(payment_methods_list)
self.payment_method_dropdown.activated.connect(
self.update_ui_for_currency_pick)
self.layout.addWidget(self.payment_method_dropdown)
self.instructions_for_currency_two = QLabel(f"Then:")
self.instructions_for_currency_two.setStyleSheet(self.lowkey_style_box)
self.instructions_for_currency_two.setWordWrap(True)
self.layout.addWidget(self.instructions_for_currency_two)
# return to main page button:
self.return_to_the_main_page_button = QPushButton("Apply the Change")
self.return_to_the_main_page_button.setStyleSheet(
"font-size: 30px; padding: 10px; background-color: green; color: yellow;")
self.return_to_the_main_page_button.clicked.connect(
self.implement_the_default_currency_change)
self.layout.addWidget(self.return_to_the_main_page_button)
# return to main page button:
self.return_to_the_main_page_button = QPushButton(
"Nevermind. Return to Main Page")
self.return_to_the_main_page_button.setStyleSheet(
"font-size: 30px; padding: 10px; background-color: red; color: black;")
self.return_to_the_main_page_button.clicked.connect(
self.update_ui_to_return_to_the_main_page)
self.layout.addWidget(self.return_to_the_main_page_button)
def update_ui_for_currency_pick(self):
self.instructions_for_currency.setStyleSheet(self.lowkey_style_box)
self.instructions_for_currency_two.setStyleSheet(self.active_style_box)
def implement_the_default_currency_change(self):
chosen_payment_method = self.payment_method_dropdown.currentText()
# It's calling on a module to change the config JSON:
self.config_file_data = replace_config_value(
self.name_of_config_file, "default_currency", chosen_payment_method)
# return back:
self.update_ui_to_return_to_the_main_page()
def email_options_ui(self):
self.clear_the_main_page_ui()
self.zero_set_of_instructions = QLabel(
f"Do you want to see options for THIS profile or ALL profiles?")
self.zero_set_of_instructions.setStyleSheet(self.active_style_box)
self.zero_set_of_instructions.setWordWrap(True)
self.layout.addWidget(self.zero_set_of_instructions)
self.display_email_data_button = QPushButton(
"THIS Profile's Email Data")
self.display_email_data_button.setStyleSheet(
"font-size: 30px; padding: 10px; background-color: blue; color: black;")
self.display_email_data_button.clicked.connect(
self.display_profile_email_data)
self.layout.addWidget(self.display_email_data_button)
self.all_profiles_email_options_button = QPushButton(
"ALL profiles Email Options")
self.all_profiles_email_options_button.setStyleSheet(
"font-size: 30px; padding: 20px; background-color: black; color: white;")
self.all_profiles_email_options_button.clicked.connect(
self.all_profile_email_options_ui)
self.layout.addWidget(self.all_profiles_email_options_button)
# return to main page button:
self.return_to_the_main_page_button = QPushButton(
"Nevermind. Return to Main Page")
self.return_to_the_main_page_button.setStyleSheet(
"font-size: 30px; padding: 10px; background-color: red; color: black;")
self.return_to_the_main_page_button.clicked.connect(
self.update_ui_to_return_to_the_main_page)
self.layout.addWidget(self.return_to_the_main_page_button)
def display_profile_email_data(self):
self.clear_the_main_page_ui()
# this is a default flag:
we_have_email_data = False # by default
packed_email_data = get_email_data() # calls function from local_logs.py
if packed_email_data == False:
message_for_end_user = "Your current profile has no email data yet."
elif packed_email_data == "error":
message_for_end_user = "There was some kind of internal error with loading the email data"
else:
we_have_email_data = True
self.email_operator_in_GUI, self.full_email_in_GUI, self.email_url_in_GUI, self.email_password_in_GUI = packed_email_data
message_for_end_user = f"""
This Profile has an Email:
Email Address: {self.full_email_in_GUI}
Web Client URL: {self.email_url_in_GUI}
Server Operator: {self.email_operator_in_GUI}
"""
# First Label displays errors OR data
self.first_set_of_instructions = QLabel(f"{message_for_end_user}")
self.first_set_of_instructions.setStyleSheet(self.active_style_box)
self.first_set_of_instructions.setWordWrap(True)
self.layout.addWidget(self.first_set_of_instructions)
if we_have_email_data == True:
# Label to copy-paste the email url:
self.copy_email_url_button = QPushButton("Copy Web Client URL")
self.copy_email_url_button.setStyleSheet(
"font-size: 15px; padding: 15px; background-color: green; color: yellow;")
self.copy_email_url_button.clicked.connect(
self.copy_email_url_function)
self.layout.addWidget(self.copy_email_url_button)
# Label to copy-paste the email:
self.copy_full_email_button = QPushButton("Copy Email")
self.copy_full_email_button.setStyleSheet(
"font-size: 20px; padding: 15px; background-color: green; color: yellow;")
self.copy_full_email_button.clicked.connect(
self.copy_full_email_function)
self.layout.addWidget(self.copy_full_email_button)
# Label to copy-paste the email password:
self.copy_email_password_button = QPushButton(
"Copy Email's Password")
self.copy_email_password_button.setStyleSheet(
"font-size: 20px; padding: 15px; background-color: green; color: yellow;")
self.copy_email_password_button.clicked.connect(
self.copy_email_password_function)
self.layout.addWidget(self.copy_email_password_button)
self.wipe_email_data_button = QPushButton("Wipe this Email Data")
self.wipe_email_data_button.setStyleSheet(
"font-size: 30px; padding: 10px; background-color: red; color: grey;")
self.wipe_email_data_button.clicked.connect(
self.call_upon_wipe_email_data_function)
self.layout.addWidget(self.wipe_email_data_button)
# return to main page button:
self.return_to_the_main_page_button = QPushButton(
"Return to Main Page")
self.return_to_the_main_page_button.setStyleSheet(
"font-size: 30px; padding: 10px; background-color: red; color: black;")
self.return_to_the_main_page_button.clicked.connect(
self.update_ui_to_return_to_the_main_page)
self.layout.addWidget(self.return_to_the_main_page_button)
def call_upon_wipe_email_data_function(self):
did_it_wipe = wipe_email_data()
if did_it_wipe == True:
message_for_end_user = "Hillary Clinton would be proud. Email data wiped."
self.copy_email_url_button.setVisible(False)
self.copy_full_email_button.setVisible(False)
self.copy_email_password_button.setVisible(False)
self.wipe_email_data_button.setVisible(False)
else:
message_for_end_user = "Some kind of File Error. Try to delete it manually"
self.first_set_of_instructions.setText(message_for_end_user)
def all_profile_email_options_ui(self):
self.clear_the_main_page_ui()
# do we have email data?
packed_email_data = get_email_data() # calls function from local_logs.py
if packed_email_data == False or packed_email_data == "error":
email_display_message = f"Do you want email to continue to be offered on the main menu for ALL profiles?"
else:
email_display_message = f"This profile already has an email. But for OTHER profiles, do you want to keep it enabled or disable it?"
# Label to display instructions
self.first_set_of_instructions = QLabel(f"{email_display_message}")
self.first_set_of_instructions.setStyleSheet(self.active_style_box)
self.first_set_of_instructions.setWordWrap(True)
self.layout.addWidget(self.first_set_of_instructions)
self.email_preference_dropdown = QComboBox()
self.email_preference_dropdown.setStyleSheet(
"color: white; background-color: green; font-size: 50px;")
list_of_email_preferences = ["yes, enable", "no, disable"]
self.email_preference_dropdown.clear()
self.email_preference_dropdown.addItems(list_of_email_preferences)
self.email_preference_dropdown.activated.connect(
self.show_the_apply_change_button)
self.layout.addWidget(self.email_preference_dropdown)
self.second_set_of_instructions = QLabel(f"Then Apply it:")
self.second_set_of_instructions.setStyleSheet(self.active_style_box)
self.second_set_of_instructions.setWordWrap(True)
self.second_set_of_instructions.setVisible(False)
self.layout.addWidget(self.second_set_of_instructions)
self.save_preferences_button = QPushButton("Apply the Change")
self.save_preferences_button.setStyleSheet(
"font-size: 30px; padding: 10px; background-color: green; color: yellow;")
self.save_preferences_button.clicked.connect(
self.implement_email_disabled_change)
self.save_preferences_button.setVisible(False)
self.layout.addWidget(self.save_preferences_button)
# return to main page button:
self.return_to_the_main_page_button = QPushButton(
"Nevermind. Return to Main Page")
self.return_to_the_main_page_button.setStyleSheet(
"font-size: 30px; padding: 10px; background-color: red; color: black;")
self.return_to_the_main_page_button.clicked.connect(
self.update_ui_to_return_to_the_main_page)
self.layout.addWidget(self.return_to_the_main_page_button)
def update_ui_to_change_local_logs(self):
self.clear_the_main_page_ui()
# Label to display change instructions
self.first_set_of_instructions = QLabel(
f"When you get an SMS code, your local computer saves the billing code so you can restore a session if disconnected, or potentially try to get the same phone number again in a future emergency. GOING FORWARD, Do you want to save this data locally? Select from the Green Dropdown below:")
self.first_set_of_instructions.setStyleSheet(self.active_style_box)
self.first_set_of_instructions.setWordWrap(True)
self.layout.addWidget(self.first_set_of_instructions)
self.local_data_preference_dropdown = QComboBox()
self.local_data_preference_dropdown.setStyleSheet(
"color: white; background-color: green; font-size: 50px;")
list_of_local_data_preferences = ["save codes", "wipe codes"]
self.local_data_preference_dropdown.clear()
self.local_data_preference_dropdown.addItems(
list_of_local_data_preferences)
self.local_data_preference_dropdown.activated.connect(
self.show_the_apply_change_button)
self.layout.addWidget(self.local_data_preference_dropdown)
self.second_set_of_instructions = QLabel(f"Then Apply it:")
self.second_set_of_instructions.setStyleSheet(self.active_style_box)
self.second_set_of_instructions.setWordWrap(True)
self.second_set_of_instructions.setVisible(False)
self.layout.addWidget(self.second_set_of_instructions)
self.save_preferences_button = QPushButton("Apply the Change")
self.save_preferences_button.setStyleSheet(
"font-size: 30px; padding: 10px; background-color: green; color: yellow;")
self.save_preferences_button.clicked.connect(
self.implement_local_data_saving_change)
self.save_preferences_button.setVisible(False)
self.layout.addWidget(self.save_preferences_button)
# return to main page button:
self.return_to_the_main_page_button = QPushButton(
"Nevermind. Return to Main Page")
self.return_to_the_main_page_button.setStyleSheet(
"font-size: 30px; padding: 10px; background-color: red; color: black;")
self.return_to_the_main_page_button.clicked.connect(
self.update_ui_to_return_to_the_main_page)
self.layout.addWidget(self.return_to_the_main_page_button)
def show_the_apply_change_button(self):
self.first_set_of_instructions.setStyleSheet(self.lowkey_style_box)
self.second_set_of_instructions.setVisible(True)
self.save_preferences_button.setVisible(True)
def implement_local_data_saving_change(self):
chosen_log_choice = self.local_data_preference_dropdown.currentText()
if chosen_log_choice == "wipe codes":
update_config_with = False
else:
update_config_with = True
# It's calling on a module to change the config JSON:
self.config_file_data = replace_config_value(
self.name_of_config_file, "local_data", update_config_with)
# return back:
self.update_ui_to_return_to_the_main_page()
def implement_email_disabled_change(self):
chosen_email_preference = self.email_preference_dropdown.currentText()
list_of_email_preferences = ["yes, enable", "no, disable"]
if chosen_email_preference == "no, disable":
turn_off_email_option = True
else:
turn_off_email_option = False
# It's calling on a module to change the config JSON:
self.config_file_data = replace_config_value(
self.name_of_config_file, "turn_off_email_option", turn_off_email_option)
# return back:
self.update_ui_to_return_to_the_main_page()
def restore_previous_session(self):
# get a list of all the locally saved past orders:
past_orders_data = return_all_locally_saved_orders_for_the_current_profile()
# setup a style for this page:
self.hipster_ecommerce_style = """
QLabel {
font-size: 14px;
font-weight: bold;
color: #333; /* Dark gray for text */
background-color: #f8f8f8; /* Light gray background */
border: 2px solid #007BFF; /* Blue border */
border-radius: 10px; /* Rounded corners */
padding: 10px; /* Padding for a spacious look */
margin: 5px; /* Margin to separate from other elements */
}
QLabel:hover {
background-color: #e0e0e0; /* Slightly darker gray on hover */
border-color: #0056b3; /* Darker blue border on hover */
}
"""
# error check if there are no past orders, or it's a new profile:
if past_orders_data == False:
self.clear_the_main_page_ui()
sorry_no_data_message = "I'm sorry, but there is no local SMS/proxy data for this profile. This could be a brand new profile, or an error with accessing your local log files."
sorry_no_data_label = QLabel(sorry_no_data_message)
sorry_no_data_label.setStyleSheet(self.hipster_ecommerce_style)
sorry_no_data_label.setWordWrap(True)
self.layout.addWidget(sorry_no_data_label)
else:
self.clear_the_main_page_ui()
# inform them it's on their local PC:
self.local_computer_data_label = QLabel(
f"This is data on your local computer. Btw you can't restore a Session you didn't pay for yet.")
self.local_computer_data_label.setStyleSheet(self.active_style_box)
self.local_computer_data_label.setWordWrap(True)
self.layout.addWidget(self.local_computer_data_label)
counter_of_how_many_rows = 0
# prep a grid layout to put them in:
self.grid_of_orders = QGridLayout()
# Create labels and buttons for each order in the list:
for each_order in past_orders_data:
# prep data:
each_billing_id, each_service, each_complete_status = each_order
# prep variables to display to the end user:
if each_complete_status == True:
display_status_to_user = "Completed"
else:
display_status_to_user = "Not yet Completed"
message_to_display_for_each_billing_id = f"{each_billing_id} with {each_service}"
each_order_label = QLabel(
message_to_display_for_each_billing_id)
each_order_label.setStyleSheet(self.hipster_ecommerce_style)
each_order_label.setWordWrap(True)
self.grid_of_orders.addWidget(
each_order_label, counter_of_how_many_rows, 0)
each_order_button = QPushButton(f"Restore {each_service}")
each_order_button.clicked.connect(
lambda checked, text=each_billing_id: self.restore_previous_session_via_button(text))
each_order_button.setStyleSheet("""
QPushButton {
font-size: 16px;
font-weight: bold;
color: white; /* White text */
background-color: #28a745; /* Green background */
border: none; /* No border */
border-radius: 5px; /* Slightly rounded corners */
padding: 12px 20px; /* Vertical and horizontal padding */
}
QPushButton:hover {
background-color: #218838; /* Darker green on hover */
}
QPushButton:pressed {
background-color: #1e7e34; /* Even darker green when pressed */
}
""")
self.grid_of_orders.addWidget(
each_order_button, counter_of_how_many_rows, 1)
each_order_delete_button = QPushButton(f"Delete")
each_order_delete_button.clicked.connect(
lambda checked, text=each_billing_id: self.delete_a_previous_session(text))
each_order_delete_button.setStyleSheet("""
QPushButton {
font-size: 15px;
font-weight: bold;
color: white; /* White text */
background-color: #FF0000; /* red background */
border: none; /* No border */
border-radius: 5px; /* Slightly rounded corners */
padding: 12px 20px; /* Vertical and horizontal padding */
}
QPushButton:hover {
background-color: #FF1000; /* Darker green on hover */
}
QPushButton:pressed {
background-color: #1e7e34; /* Even darker green when pressed */
}
""")
self.grid_of_orders.addWidget(
each_order_delete_button, counter_of_how_many_rows, 2)
# this counter is for the grid layout:
counter_of_how_many_rows = counter_of_how_many_rows + 1
try:
self.layout.addLayout(self.grid_of_orders)
except:
print("no grid layout because it's an empty profile config.")
# manually enter billing code button:
self.enter_manually_button = QPushButton(
"Or Manually Enter a Billing Code")
self.enter_manually_button.setStyleSheet(self.blue_chill_style)
self.enter_manually_button.clicked.connect(
self.manually_restore_previous_session)
self.layout.addWidget(self.enter_manually_button)
# return to main page button:
self.return_to_the_main_page_button = QPushButton(
"Nevermind. Return to Main Page")
self.return_to_the_main_page_button.setStyleSheet(
"font-size: 30px; padding: 10px; background-color: red; color: black;")
self.return_to_the_main_page_button.clicked.connect(
self.update_ui_to_return_to_the_main_page)
self.layout.addWidget(self.return_to_the_main_page_button)
def remove_grid_layout(self):
try:
# Remove the grid layout from the main layout
self.layout.removeItem(self.grid_of_orders)
# Delete all widgets in the grid layout
for i in range(self.grid_of_orders.count()):
widget = self.grid_of_orders.itemAt(i).widget()
if widget:
widget.deleteLater() # Safely delete the widget
# Delete the grid layout itself
del self.grid_of_orders
except:
print("no grid")
def delete_a_previous_session(self, order):
delete_an_order(order)
self.update_ui_to_return_to_the_main_page()
def restore_previous_session_via_button(self, order):
try:
# Call the method to remove the grid layout
self.remove_grid_layout()
except:
pass
self.peer_to_peer_billing_id = order
self.restore_previous_session_function(self.peer_to_peer_billing_id)
# start: restore previous section
def manually_restore_previous_session(self):
text, ok = QInputDialog.getText(
self, 'Restore Previous Session', 'Enter your billing ID:')
if ok: # If the user clicked ok:
self.process_input(text)
def process_input(self, input_text):
try:
# Call the method to remove the grid layout
self.remove_grid_layout()
except:
pass
# Save the input text as a variable
self.input_variable = input_text
# Show the input in a message box
QMessageBox.information(
self, "Restore", f"You entered: {self.input_variable}")
# save the input as the buyer billing id:
self.peer_to_peer_billing_id = self.input_variable
# commented this out for the new options menu flow:
# remove the main button, since it's not being removed by the upcoming function as we return to normal flow:
# self.button.deleteLater()
self.restore_previous_session_function(self.peer_to_peer_billing_id)
# end: restore previous section
def on_right_item_clicked(self, item):
# We're filling in the locations that are available for that selected service on the right column/box:
selected_service = item.text()
list_of_locations = get_the_locations_for_a_service(
self.initial_data, selected_service)
self.location_dropdown.clear()
# Get Locally Saved Profile Data:
profile_location_and_proxy_tuple = get_profile_location_and_proxy_status_as_tuple()
# Now we find out if it's a Pre-existing Profile
if profile_location_and_proxy_tuple == False:
# Since it's a new profile, we need to setup a location selection:
self.location_dropdown.addItems(list_of_locations)
# For a new profile, now that they selected a service from the right column, show the send button at bottom:
self.button.setVisible(True)
self.turn_off_email_option = search_key_in_json(
self.config_file_data, "turn_off_email_option", False)
if self.turn_off_email_option == True:
self.button.setText("Residential Proxy and SMS (€10)")
# they can also get only SMS for a new profile:
self.just_sms_button.setVisible(True)
self.label_for_profile_status.setText(
f"Based on your local data, this is a new profile, that has not yet been assigned a residential proxy")
else:
# Pre-existing profiles have a location already, so they don't need to pick:
profile_location, profile_proxy_status = profile_location_and_proxy_tuple
# check if this service is available for the pre-existing profile location:
if profile_location in list_of_locations:
# display that location is available:
only_that_location_list = [profile_location]
self.location_dropdown.addItems(only_that_location_list)
# they can only buy SMS or email for this service,
self.just_sms_button.setVisible(True)
self.label_for_profile_status.setText(
f"Your locally saved data shows this profile has a proxy already for {profile_location}. But you can get more SMS numbers or emails. If you want to pick a new location, please make a new browser fingerprint profile.")
else:
self.label_for_profile_status.setText(
f"That service is not available for {profile_location}. Your locally saved data shows this profile has a proxy for {profile_location}")
self.label_for_profile_status.setVisible(True)
def on_item_clicked(self, item):
# Get the selected item's text
selected_item = item.text()
# Retrieve the corresponding list from the mapping
new_list = self.list_mapping.get(selected_item, [])
self.update_list_widget(new_list)
def update_list_widget(self, new_list):
# this clears the existing items from the list and adds the new ones when the selection on the left changes:
self.list_widget2.clear()
self.list_widget2.addItems(new_list)
@asyncSlot()
async def on_dispute_button_click(self):
asyncio.create_task(self.dispute_send_to_flask("dispute_new_seller"))
@asyncSlot()
async def on_yes_button_click(self):
asyncio.create_task(self.dispute_send_to_flask("yes_worked"))
@asyncSlot()
async def just_sms_no_proxy(self):
# this is for NO proxy:
self.proxy_status = False
# Step 1: Run the async function
asyncio.create_task(self.button_pushed_send_to_flask())
# Step 2: Show dialog and hide button after a short delay
QTimer.singleShot(0, self.show_dialog_and_hide_button)
@asyncSlot() # Decorator to allow this method to be async
async def on_button_click(self):
# this is for a PROXY:
self.proxy_status = True
# Step 1: Run the async function
asyncio.create_task(self.button_pushed_send_to_flask())
# Step 2: Show dialog and hide button after a short delay
QTimer.singleShot(0, self.show_dialog_and_hide_button)
def show_dialog_and_hide_button(self):
self.show_dialog()
try:
self.button.hide()
except:
pass
try:
self.just_sms_button.hide()
except:
pass
def show_dialog(self):
msg = QMessageBox()
msg.setText("Sent! Wait a few seconds")
msg.exec()
# Start: Send data to Flask Section:
async def button_pushed_send_to_flask(self):
# get data from dropdowns to send to the API:
chosen_payment_method = self.payment_method_dropdown.currentText()
uppercase_chosen_location = self.location_dropdown.currentText()
chosen_location = uppercase_chosen_location.lower()
selected_items = self.list_widget2.selectedItems()
chosen_service_as_string = selected_items[0].text()
# email section:
uppercase_chosen_email = self.email_dropdown.currentText()
self.chosen_email = filter_email_names(uppercase_chosen_email)
# could uncomment for debug:
# print(f"This is the chosen service as a string: {chosen_service_as_string}")
# Send this data to the Flask server:
returned_data = await send_data_to_flask(chosen_payment_method, chosen_location, chosen_service_as_string, self.chosen_email, self.proxy_status, self.peer_to_peer_billing_id)
print(f"this is data: {returned_data}")
# self.record_of_complete = True
accepted_codes = [200, 201]
rejected_codes = [400, 401, 404]
# We're checking if it returned an error or registered the user:
if 'message' in returned_data:
message = returned_data['message']
if message == "Registered" or message == "registered":
# It replied with crypto addresses, we're game on,
# First, Reload the Config data because we want to see if the user doesn't want logs:
self.config_file_data = load_or_setup_config(
self.name_of_config_file)
# We're checking if they want logs, and if they do we're now updating the Local Logs, to make or update the profile:
did_it_work = create_or_add_to_profile_config(
self.config_file_data, self.peer_to_peer_billing_id, chosen_location, self.proxy_status, chosen_service_as_string, self.chosen_email)
if did_it_work == "error":
print("Error with saving billing code to local log")
# Update the GUI with the crypto addresses and begin process:
self.update_ui(returned_data)
else:
# Display Errors:
self.update_ui_for_errors(message)
# Display Connection Errors:
elif 'error' in returned_data:
connection_error_is = returned_data['error']
self.update_ui_for_errors(connection_error_is)
else:
self.update_ui_for_errors(returned_data)
return returned_data
# End: Send data to Flask Section
# Start: DISPUTE Send data to Flask Section:
async def dispute_send_to_flask(self, how_did_it_go):
# Send this data to the Flask server
returned_data = await dispute_send_data_to_flask(how_did_it_go, self.peer_to_peer_billing_id)
filter_returned_data_message = returned_data.get('message')
# self.record_of_complete = True # not sure if I need this line anymore
# Update the UI if the dispute was accepted or rejected.
# filter_returned_data_message is what the API returned
# how_did_it_go is how the user said it went.
if how_did_it_go == "dispute_new_seller":
if filter_returned_data_message == "dispute_accepted":
# Dispute accepted:
self.update_ui_for_dispute()
else:
# Dispute Rejected:
self.update_ui_for_dispute_rejected()
elif how_did_it_go == "yes_worked":
# NOT disputed, accepted:
self.update_ui_for_peaceful_finalized_acceptance()
return returned_data
# End: DISPUTE send to Flask Section
# Start SECOND: Send data to Flask Section, CHECK PAYMENT.
@asyncSlot() # Decorator to allow this method to be async
async def check_if_paid_on_timer(self):
# Step 1: Run the async function
asyncio.create_task(self.check_payment_button_pushed_send_to_flask())
# Step 2: Show dialog and hide button after a short delay
# QTimer.singleShot(0, self.show_dialog_and_hide_button)
# def show_dialog_and_hide_button(self):
# self.show_dialog()
# self.button.hide()
async def check_payment_button_pushed_send_to_flask(self):
# Send this data to the Flask server
returned_data = await check_if_paid_by_sending_data_to_flask(self.peer_to_peer_billing_id)
print(f"this is data: {returned_data}")
# self.record_of_complete = True
# Update the GUI with the response on if it's paid and the SMS status:
self.update_ui_after_checking_if_paid(returned_data)
return returned_data
def show_an_error(self, error_message):
msg = QMessageBox()
msg.setText(f"{error_message}")
msg.exec()
def update_ui_after_checking_if_paid(self, returned_data):
try:
if isinstance(returned_data, dict):
# Directly use the dictionary
returned_data_as_a_dictionary = returned_data
else:
# If it's a string, format it and load it as a dictionary
valid_json_string = returned_data.replace("'", '"')
returned_data_as_a_dictionary = json.loads(valid_json_string)
# Get the data from that:
self.payment_status_in_GUI = returned_data_as_a_dictionary.get(
'payment_status')
self.code_status_in_GUI = returned_data_as_a_dictionary.get(
'code_status')
# this is used further down, and it's for also checking if it's in the restoration flow:
list_of_all_types_of_confirmed = ["confirmed", "restore_confirmed"]
# if it's already given a code, move to next screen:
if self.code_status_in_GUI == "send_code_to_buyer":
# Stop checking if it's paid, we're past that if it's "send_code_to_buyer":
self.timer.stop()
# update UI to get code, and switch to code endpoint:
self.update_ui_after_to_get_code()
elif self.code_status_in_GUI == "already_finalized":
# Stop checking if it's paid, we're past that if it's "send_code_to_buyer":
self.timer.stop()
# update UI to get code, and switch to code endpoint:
self.bring_trade_back_from_dead()
# If it's fully paid, then we're giving the proxy info, so check if paid:
elif self.code_status_in_GUI == "rejected":
# Stop checking if it's paid:
self.timer.stop()
elif self.code_status_in_GUI == "First Seller has 10 minutes to confirm":
self.update_status_label.setStyleSheet(self.lowkey_style_box)
self.update_sms_status_label.setStyleSheet(
self.active_style_box)
elif "refund_crypto" in returned_data_as_a_dictionary:
# this is triggered when we're doing a refund,
self.refund_crypto = returned_data_as_a_dictionary.get(
'refund_crypto')
self.timer.stop()
# get the refund crypto address with a text box,
self.refund_crypto_text_box = QLineEdit(self)
# Set the size policy to make the box bigger
self.refund_crypto_text_box.setMinimumSize(300, 40)
# Set the stylesheet for the grey background
self.refund_crypto_text_box.setStyleSheet(
"background-color: blue;")
self.refund_crypto_text_box.setPlaceholderText(
f"Enter your {self.refund_crypto} refund address")
self.layout.addWidget(self.refund_crypto_text_box)
# button to submit crypto address:
self.button_to_submit_the_refund_address = QPushButton(
f"Submit {self.refund_crypto} Address")
self.button_to_submit_the_refund_address.setStyleSheet(
"font-size: 20px; padding: 30px; background-color: green; color: yellow;")
self.button_to_submit_the_refund_address.clicked.connect(
self.gui_calls_send_crypto_address_for_refund)
self.layout.addWidget(self.button_to_submit_the_refund_address)
# If it's fully paid and confirmed, then we're moving on to the next section with giving the phone number:
elif self.payment_status_in_GUI == "paid" and self.code_status_in_GUI in list_of_all_types_of_confirmed:
# Get the phone number and set variable to display it:
self.assigned_phone_number_in_GUI = returned_data_as_a_dictionary.get(
'assigned_phone_number')
if self.code_status_in_GUI == "restore_confirmed":
self.display_code_status_in_GUI = f"The Seller is Ready to Restore. If you need the Phone number, then it's {self.assigned_phone_number_in_GUI}. Hit 'copy' to proceed."
else:
self.display_code_status_in_GUI = f"Step 1. Go sign-up for the service. Phone number is {self.assigned_phone_number_in_GUI}"
# check if there's proxy data, and if so then process it:
if "proxy_ip_address" in returned_data_as_a_dictionary:
process_the_proxy(returned_data_as_a_dictionary)
else:
print("No Proxy")
# Stop checking if it's paid & confirmed:
self.timer.stop()
# check if there's email data,
if "full_email" in returned_data_as_a_dictionary:
self.full_email_in_GUI = returned_data_as_a_dictionary.get(
'full_email')
self.email_password_in_GUI = returned_data_as_a_dictionary.get(
'email_password')
self.email_url_in_GUI = returned_data_as_a_dictionary.get(
'email_url')
self.email_operator_in_GUI = returned_data_as_a_dictionary.get(
'email_operator_name')
self.display_code_status_in_GUI = f"Step 2. Phone number is {self.assigned_phone_number_in_GUI}"
# save it,
# if we recieved this email data in the same session as the initial order, then self.chosen_email has the operator
try:
did_it_create_config = setup_email_config(
self.email_operator_in_GUI, self.full_email_in_GUI, self.email_password_in_GUI, self.email_url_in_GUI)
print(f"did_it_create_config: {did_it_create_config}")
except:
print("Internal error with saving the email data")
else:
print("No Email")
self.full_email_in_GUI = None
# Update the GUI for the whole next section on the phone number:
self.update_ui_after_getting_phone_number()
# end confirmed section
# Start: PROCESS SECTION
# But if it's just processing, we can slow the timer during this:
elif self.payment_status_in_GUI == "processing":
self.timer.start(9000)
else:
print("checked, but it's not showing yet")
# self.sms_status_in_GUI = "Waiting on Payment"
# Paid or Not, update the label:
try:
# if restore flow..
if self.payment_status_in_GUI == "not_paid":
self.update_status_label.setText(
f"Payment Status: Not yet Paid. Please pay")
# self.update_status_label.styleSheet(self.active_style_box)
else: # normal flow:
self.update_status_label.setText(
f"Payment Status: {self.payment_status_in_GUI}")
except RuntimeError:
print(
"You're trying to change the text of a label, but it's already been deleted.")
try:
# doing more restore flow here, this is because for the original flow the messages were server-side, for the restore flow I switched to client-side:
if self.code_status_in_GUI == "restore_confirmed":
self.update_sms_status_label.setText(
f"SMS Status: Seller for your specific restore number is ready.")
try:
if self.the_returned_crypto_address_is:
pass
# Except should trigger if this guy is restoring, but lost his crypto address.
except:
# so stop checking if he paid:
self.timer.stop()
# and let him get a new address:
self.get_new_address_button = QPushButton(
"Get a New Address")
self.get_new_address_button.setStyleSheet(
"font-size: 15px; padding: 15px; background-color: green; color: yellow;")
self.get_new_address_button.clicked.connect(
self.yes_pay_to_restore_send)
self.layout.addWidget(self.get_new_address_button)
else: # normal flow (non restore)
self.update_sms_status_label.setText(
f"SMS Status: {self.code_status_in_GUI}")
except RuntimeError:
print(
"You're trying to change the text of a label, but it's already been deleted.")
except json.JSONDecodeError as e:
print(f"JSON decoding error: {e}")
# Stop checking if it can't format the JSON:
self.timer.stop()
return
# donkey cunt
except Exception as e:
exc_type, exc_value, exc_tb = sys.exc_info()
tb_summary = traceback.extract_tb(exc_tb)
# Get the line number of the error
line_number = tb_summary[-1].lineno
error_msg = f"An error on line {line_number} produced: {e}"
print(error_msg)
self.show_an_error(f"Error occurred: {e}")
# stop checking:
self.timer.stop()
def update_ui_after_getting_phone_number(self):
# first clear layouts:
try:
for i in reversed(range(self.grid_layout.count())):
item = self.grid_layout.itemAt(i)
if item is not None:
widget = item.widget()
if widget is not None:
widget.deleteLater()
except:
print("No Grid layout")
for i in reversed(range(self.layout.count())):
item = self.layout.itemAt(i)
if item is not None:
widget = item.widget()
if widget is not None:
widget.deleteLater()
# Is there email data?
if self.full_email_in_GUI is not None:
# Label to display the email:
self.full_email_label = QLabel(
f"Step 1. Go sign-up for the service. Email is {self.full_email_in_GUI}")
self.full_email_label.setStyleSheet(self.active_style_box)
self.full_email_label.setWordWrap(True)
self.layout.addWidget(self.full_email_label)
# Label to copy-paste the email url:
self.copy_email_url_button = QPushButton("Copy Email's URL")
self.copy_email_url_button.setStyleSheet(
"font-size: 15px; padding: 15px; background-color: green; color: yellow;")
self.copy_email_url_button.clicked.connect(
self.copy_email_url_function)
self.layout.addWidget(self.copy_email_url_button)
# Label to copy-paste the email:
self.copy_full_email_button = QPushButton("Copy Email")
self.copy_full_email_button.setStyleSheet(
"font-size: 20px; padding: 15px; background-color: green; color: yellow;")
self.copy_full_email_button.clicked.connect(
self.copy_full_email_function)
self.layout.addWidget(self.copy_full_email_button)
# Label to copy-paste the email password:
self.copy_email_password_button = QPushButton(
"Copy Email's Password")
self.copy_email_password_button.setStyleSheet(
"font-size: 20px; padding: 15px; background-color: green; color: yellow;")
self.copy_email_password_button.clicked.connect(
self.copy_email_password_function)
self.layout.addWidget(self.copy_email_password_button)
# Label to display the phone number:
self.after_confirm_sms_status_label = QLabel(
f"{self.display_code_status_in_GUI}")
self.after_confirm_sms_status_label.setStyleSheet(
self.active_style_box)
self.after_confirm_sms_status_label.setWordWrap(True)
self.after_confirm_sms_status_label.setFixedWidth(800)
self.after_confirm_sms_status_label.setMaximumHeight(250)
self.layout.addWidget(self.after_confirm_sms_status_label)
# Label to copy-paste the phone number:
# flag variable for the apperance of the button in copy_phone_number_function in the next step, which this button triggers
self.get_code_button_already_visible = False
self.copy_phone_number_button = QPushButton("Copy Phone Number")
self.copy_phone_number_button.setStyleSheet(
"font-size: 30px; padding: 15px; background-color: green; color: yellow;")
self.copy_phone_number_button.clicked.connect(
self.copy_phone_number_function)
self.layout.addWidget(self.copy_phone_number_button)
# Label to display instructions:
self.label_for_instructions = QLabel(
f"After that service sends the SMS code to that number, THEN hit the button below.")
self.label_for_instructions.setStyleSheet(self.lowkey_style_box)
# self.label_for_instructions.setStyleSheet("font-size: 20px;")
self.label_for_instructions.setWordWrap(True)
self.label_for_instructions.setFixedWidth(800)
self.label_for_instructions.setMaximumHeight(300)
self.layout.addWidget(self.label_for_instructions)
self.label_for_instructions.setVisible(False)
# Start: Display the Code Section
@asyncSlot() # Decorator to allow this method to be async
async def with_slot_async_get_code_function(self):
# Step 1: Run the async function
asyncio.create_task(self.send_to_get_code_function())
async def send_to_get_code_function(self):
# Send this data to the Flask server
returned_data = await ready_for_code_by_sending_data_to_flask(self.peer_to_peer_billing_id)
# DEBUG SECTION! uncomment to debug,
# print (f"this is data: {returned_data}")
# self.record_of_complete = True
# Update the GUI with the response data
self.update_ui_after_checking_for_code(returned_data)
return returned_data
def update_ui_after_checking_for_code(self, returned_data):
try:
if isinstance(returned_data, dict):
# Directly use the dictionary
returned_data_as_a_dictionary = returned_data
else:
# If it's a string, format it and load it as a dictionary
valid_json_string = returned_data.replace("'", '"')
returned_data_as_a_dictionary = json.loads(valid_json_string)
# Get the data from that:
self.code_status_in_GUI = returned_data_as_a_dictionary.get(
'code_status')
self.code_in_GUI = returned_data_as_a_dictionary.get(
'assigned_code')
if self.code_in_GUI is None:
self.code_in_GUI = "Please wait"
elif self.code_status_in_GUI == "timed_out_buyer":
# stop timer to check for code and display the "code" which is just telling them they took too long:
self.get_code_timer.stop()
self.after_requesting_code_label.setText(
f"Please close this window and try again. {self.code_in_GUI}")
# else triggered means they got a code. They weren't timed out and it isn't still waiting
else:
if self.label_for_instructions.styleSheet() == self.active_style_box:
pass
else:
self.after_requesting_code_label.setStyleSheet(
self.active_style_box)
# this was the original way of doing it, prior to the upgrade of universal styles in the __init__
# self.after_requesting_code_label.setStyleSheet("font-size: 50px;")
# self.label_for_instructions.setStyleSheet("font-size: 50px;")
# print it out for debug status:
print(self.code_status_in_GUI)
print(self.code_in_GUI)
# display code in GUI:
if self.code_in_GUI == "Please wait":
self.after_requesting_code_label.setText(
f"Contacting Seller to Fetch the Code. Make sure you told the website to send it.")
self.after_requesting_code_label.setStyleSheet(
self.active_style_box)
else:
self.after_requesting_code_label.setText(
f"Code: {self.code_in_GUI}")
self.copy_paste_code.setVisible(True)
# stop timer to check:
self.get_code_timer.stop()
except:
print("No code yet")
def update_ui_after_to_get_code(self):
# first clear layouts:
for i in reversed(range(self.layout.count())):
item = self.layout.itemAt(i)
if item is not None:
widget = item.widget()
if widget is not None:
widget.deleteLater()
# We're doing a 2 second timer to check if the code is ready from API:
self.timer = QTimer()
self.timer.timeout.connect(self.with_slot_async_get_code_function)
self.timer.start(2000)
# Label to display the code:
self.code_in_GUI = "Getting Seller's Reply..."
self.after_requesting_code_label = QLabel(f"{self.code_in_GUI}")
self.after_requesting_code_label.setStyleSheet(
"background-color: white; color: black; font-size: 30px;")
self.after_requesting_code_label.setWordWrap(True)
self.after_requesting_code_label.setFixedWidth(800)
self.after_requesting_code_label.setMaximumHeight(250)
self.layout.addWidget(self.after_requesting_code_label)
# button to copy-paste the code:
self.copy_paste_code = QPushButton("Copy Code")
self.copy_paste_code.setStyleSheet(
"font-size: 30px; padding: 15px; background-color: green; color: yellow;")
self.copy_paste_code.clicked.connect(self.copy_code_function)
self.layout.addWidget(self.copy_paste_code)
self.copy_paste_code.setVisible(False)
# Label to display instructions:
self.label_for_instructions = QLabel(f"Did this work?")
self.label_for_instructions.setStyleSheet(self.lowkey_style_box)
self.label_for_instructions.setWordWrap(True)
self.label_for_instructions.setFixedWidth(800)
self.label_for_instructions.setMaximumHeight(200)
self.layout.addWidget(self.label_for_instructions)
# End: Display the Code Section
# Start: Display the Error Section:
def update_ui_for_errors(self, returned_data_as_dict):
returned_data = str(returned_data_as_dict)
# Clear all widgets from the vertical layout
for i in reversed(range(self.layout.count())):
item = self.layout.itemAt(i)
if item is not None:
widget = item.widget()
if widget is not None:
widget.deleteLater()
# Clear all widgets from the horizontal layout
for i in reversed(range(self.h_layout.count())):
item = self.h_layout.itemAt(i)
if item is not None:
widget = item.widget()
if widget is not None:
widget.deleteLater()
for i in reversed(range(self.top_ribbon_h_layout.count())):
item = self.top_ribbon_h_layout.itemAt(i)
if item is not None:
widget = item.widget()
if widget is not None:
widget.deleteLater()
# Display the header label for the Error page (with the label style declared in the init section)
label_for_peer_to_peer_billing_id = QLabel(
f"Error! Something went wrong")
label_for_peer_to_peer_billing_id.setStyleSheet(self.label_style)
label_for_peer_to_peer_billing_id.setSizePolicy(
QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
self.layout.addWidget(label_for_peer_to_peer_billing_id)
# This label gives the raw error message in a box:
self.update_status_label = QLabel(returned_data)
self.update_status_label.setStyleSheet(
"background-color: white; color: black; font-size: 25px;")
self.update_status_label.setWordWrap(True)
self.update_status_label.setFixedWidth(700)
self.update_status_label.setMaximumHeight(400)
self.layout.addWidget(self.update_status_label)
# Start: Display the Result Section:
# We're displaying the crypto payment data and SMS status windows:
def update_ui(self, returned_data):
self.the_returned_crypto_address_is = returned_data.get('address')
self.the_returned_crypto_amount_is = returned_data.get('amount_owed')
# Clear the layout and display the new label with the data
# Clear all widgets from the vertical layout
for i in reversed(range(self.layout.count())):
item = self.layout.itemAt(i)
if item is not None:
widget = item.widget()
if widget is not None:
widget.deleteLater()
# Clear all widgets from the horizontal layout
for i in reversed(range(self.h_layout.count())):
item = self.h_layout.itemAt(i)
if item is not None:
widget = item.widget()
if widget is not None:
widget.deleteLater()
for i in reversed(range(self.top_ribbon_h_layout.count())):
item = self.top_ribbon_h_layout.itemAt(i)
if item is not None:
widget = item.widget()
if widget is not None:
widget.deleteLater()
# Display the ID:
label_for_peer_to_peer_billing_id = QLabel(
f"Your P2P ID: {self.peer_to_peer_billing_id}")
label_for_peer_to_peer_billing_id.setStyleSheet(self.label_style)
label_for_peer_to_peer_billing_id.setWordWrap(True)
label_for_peer_to_peer_billing_id.setSizePolicy(
# Expanding vertical size policy
QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
self.layout.addWidget(label_for_peer_to_peer_billing_id)
# Create a button to Copy Paste ID:
self.copy_amount_button = QPushButton("Copy Your Billing ID")
# Set background and text color self.button.clicked.connect(self.show_selected)
self.copy_amount_button.setStyleSheet(
"font-size: 20px; padding: 20px; background-color: green; color: yellow;")
self.copy_amount_button.clicked.connect(self.copy_billing_id_function)
self.layout.addWidget(self.copy_amount_button)
# Create new labels with the response data
crypto_long_address_as_string = str(
self.the_returned_crypto_address_is)
length_of_long_address = len(crypto_long_address_as_string)
# Litecoin is 43, so let's see if it's long enough for one line, if so break it up:
if length_of_long_address >= 44:
break_into_three = length_of_long_address / 2
import math
round_up_breaking_into_three_groups = math.ceil(break_into_three)
first_group = crypto_long_address_as_string[0:
round_up_breaking_into_three_groups]
second_group = crypto_long_address_as_string[
round_up_breaking_into_three_groups:length_of_long_address]
else:
# probably litecoin, so one line:
first_group = crypto_long_address_as_string
second_group = ""
# Create a QGridLayout
self.grid_layout = QGridLayout()
# This next section creates four widgets to add to the grid layout for the crypto data and copy buttons,
# Address Label:
self.address_label = QLabel(f"{first_group}\n{second_group}")
self.address_label.setWordWrap(True)
self.address_label.setFixedWidth(600)
self.address_label.setMaximumHeight(100)
self.address_label.setStyleSheet(
"background-color: grey; color: black; font-size: 15px;")
self.layout.addWidget(self.address_label)
# Create a button to Copy Paste Address
self.copy_crypto_address_button = QPushButton("Copy Address")
self.copy_crypto_address_button.setStyleSheet(
# Set background and text color
"font-size: 30px; padding: 15px; background-color: green; color: yellow;")
self.copy_crypto_address_button.clicked.connect(
self.copy_crypto_address_function)
self.layout.addWidget(self.copy_crypto_address_button)
# Amount label:
self.amount_label = QLabel(str(self.the_returned_crypto_amount_is))
self.amount_label.setStyleSheet(
"background-color: grey; color: black; font-size: 20px;")
self.amount_label.setFixedWidth(600)
self.amount_label.setMaximumHeight(100)
self.layout.addWidget(self.amount_label)
# Create a button to Copy Paste Amount
self.copy_amount_button = QPushButton("Copy Amount")
# Set background and text color self.button.clicked.connect(self.show_selected)
self.copy_amount_button.setStyleSheet(
"font-size: 30px; padding: 30px; background-color: green; color: yellow;")
self.copy_amount_button.clicked.connect(self.copy_amount_function)
self.layout.addWidget(self.copy_amount_button)
# Add widgets to the grid layout
self.grid_layout.addWidget(self.address_label, 0, 0) # Row 0, Column 0
self.grid_layout.addWidget(
self.copy_crypto_address_button, 0, 1) # Row 0, Column 1
self.grid_layout.addWidget(self.amount_label, 1, 0) # Row 1, Column 0
self.grid_layout.addWidget(
self.copy_amount_button, 1, 1) # Row 1, Column 1
# Add the grid layout to the main layout
self.layout.addLayout(self.grid_layout)
# Payment check label:
self.update_status_label = QLabel("Payment Checker: Connecting..")
self.update_status_label.setStyleSheet(self.active_style_box)
self.update_status_label.setWordWrap(True)
self.update_status_label.setFixedWidth(800)
self.update_status_label.setMaximumHeight(120)
self.layout.addWidget(self.update_status_label)
# SMS status label:
self.update_sms_status_label = QLabel("SMS Status: Connecting..")
self.update_sms_status_label.setStyleSheet(self.lowkey_style_box)
self.update_sms_status_label.setWordWrap(True)
self.update_sms_status_label.setFixedWidth(800)
self.update_sms_status_label.setMaximumHeight(250)
self.layout.addWidget(self.update_sms_status_label)
# Create a timer
self.timer = QTimer()
self.timer.timeout.connect(self.check_if_paid_on_timer)
self.timer.start(5000) # Start the timer with a 5-second interval
def restore_previous_session_function(self, buyer_billing_id_entered):
# Clear the layout and display the new label with the data
try:
# Clear all widgets from the vertical layout
for i in reversed(range(self.layout.count())):
item = self.layout.itemAt(i)
if item is not None:
widget = item.widget()
if widget is not None:
widget.deleteLater()
# Clear all widgets from the horizontal layout
for i in reversed(range(self.h_layout.count())):
item = self.h_layout.itemAt(i)
if item is not None:
widget = item.widget()
if widget is not None:
widget.deleteLater()
for i in reversed(range(self.top_ribbon_h_layout.count())):
item = self.top_ribbon_h_layout.itemAt(i)
if item is not None:
widget = item.widget()
if widget is not None:
widget.deleteLater()
except:
pass
finally:
# Payment check label:
self.update_status_label = QLabel("Payment Checker: Connecting..")
self.update_status_label.setStyleSheet(
"background-color: white; color: black; font-size: 30px;")
self.update_status_label.setFixedWidth(700)
self.update_status_label.setMaximumHeight(100)
self.layout.addWidget(self.update_status_label)
# Amount label:
self.update_sms_status_label = QLabel("SMS Status: Connecting..")
self.update_sms_status_label.setStyleSheet(
"background-color: white; color: black; font-size: 30px;")
self.update_sms_status_label.setWordWrap(True)
self.update_sms_status_label.setFixedWidth(800)
self.update_sms_status_label.setMaximumHeight(250)
self.layout.addWidget(self.update_sms_status_label)
# Create a timer
self.timer = QTimer()
self.timer.timeout.connect(self.check_if_paid_on_timer)
self.timer.start(5000) # Start the timer with a 5-second interval
def copy_crypto_address_function(self):
clipboard = QApplication.clipboard()
clipboard.setText(self.the_returned_crypto_address_is)
def copy_amount_function(self):
clipboard = QApplication.clipboard()
clipboard.setText(self.the_returned_crypto_amount_is)
def copy_billing_id_function(self):
clipboard = QApplication.clipboard()
clipboard.setText(self.peer_to_peer_billing_id)
def copy_code_function(self):
clipboard = QApplication.clipboard()
clipboard.setText(self.code_in_GUI)
if self.code_in_GUI is not None:
self.after_requesting_code_label.setStyleSheet(
self.lowkey_style_box)
self.label_for_instructions.setStyleSheet(self.active_style_box)
# Yes Button:
self.yes_button = QPushButton("Yes")
self.yes_button.setStyleSheet(
"font-size: 30px; padding: 15px; background-color: green; color: yellow;")
self.yes_button.clicked.connect(self.on_yes_button_click)
self.layout.addWidget(self.yes_button)
# No Button:
self.no_button = QPushButton("No, try a NEW seller & number")
self.no_button.setStyleSheet(
"font-size: 15px; padding: 15px; background-color: red; color: black;")
self.no_button.clicked.connect(self.on_dispute_button_click)
self.layout.addWidget(self.no_button)
def hide_crypto_address_grid_layout(self):
for i in range(self.grid_layout.count()):
widget = self.grid_layout.itemAt(i).widget()
if widget is not None:
widget.hide()
def copy_full_email_function(self):
clipboard = QApplication.clipboard()
clipboard.setText(self.full_email_in_GUI)
def copy_email_password_function(self):
clipboard = QApplication.clipboard()
clipboard.setText(self.email_password_in_GUI)
try:
self.full_email_label.setStyleSheet(self.lowkey_style_box)
except:
pass
def copy_email_url_function(self):
clipboard = QApplication.clipboard()
clipboard.setText(self.email_url_in_GUI)
def copy_phone_number_function(self):
clipboard = QApplication.clipboard()
clipboard.setText(self.assigned_phone_number_in_GUI)
self.after_confirm_sms_status_label.setStyleSheet(
self.lowkey_style_box)
self.label_for_instructions.setStyleSheet(self.active_style_box)
self.label_for_instructions.setVisible(True)
try:
self.full_email_label.setVisible(False)
except:
pass
# only add this button if it isn't already visible or added:
if self.get_code_button_already_visible == False:
self.ready_to_get_code_button = QPushButton("Step 3. Get the Code")
self.ready_to_get_code_button.setStyleSheet(
"font-size: 30px; padding: 15px; background-color: green; color: yellow;")
self.ready_to_get_code_button.clicked.connect(
self.update_ui_after_to_get_code)
self.layout.addWidget(self.ready_to_get_code_button)
self.get_code_button_already_visible = True
# End: Display the Result Section
# Start: Dispute display UI
# Start: Dispute ACCEPTED Display the Result Section:
def update_ui_for_dispute(self):
# Clear the layout and display the new label with the data
# Clear all widgets from the vertical layout
for i in reversed(range(self.layout.count())):
item = self.layout.itemAt(i)
if item is not None:
widget = item.widget()
if widget is not None:
widget.deleteLater()
# Clear all widgets from the horizontal layout
for i in reversed(range(self.h_layout.count())):
item = self.h_layout.itemAt(i)
if item is not None:
widget = item.widget()
if widget is not None:
widget.deleteLater()
# Display the ID:
label_for_peer_to_peer_billing_id = QLabel(
f"Dispute! Matching you with a New Number. {self.peer_to_peer_billing_id}")
label_for_peer_to_peer_billing_id.setStyleSheet(self.label_style)
label_for_peer_to_peer_billing_id.setWordWrap(True)
label_for_peer_to_peer_billing_id.setSizePolicy(
# Expanding vertical size policy
QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
self.layout.addWidget(label_for_peer_to_peer_billing_id)
# Create a button to Copy Paste ID:
self.copy_amount_button = QPushButton("Copy Your Billing ID")
# Set background and text color self.button.clicked.connect(self.show_selected)
self.copy_amount_button.setStyleSheet(
"font-size: 20px; padding: 20px; background-color: green; color: yellow;")
self.copy_amount_button.clicked.connect(self.copy_billing_id_function)
self.layout.addWidget(self.copy_amount_button)
# Payment check label:
self.update_status_label = QLabel("Payment Paid")
self.update_status_label.setStyleSheet(
"background-color: white; color: black; font-size: 30px;")
self.update_status_label.setFixedWidth(700)
self.update_status_label.setMaximumHeight(100)
self.layout.addWidget(self.update_status_label)
# Status label:
self.update_sms_status_label = QLabel("SMS Status: Connecting..")
self.update_sms_status_label.setStyleSheet(
"background-color: white; color: black; font-size: 30px;")
self.update_sms_status_label.setWordWrap(True)
self.update_sms_status_label.setFixedWidth(800)
self.update_sms_status_label.setMaximumHeight(250)
self.layout.addWidget(self.update_sms_status_label)
# Create a timer
self.timer = QTimer()
self.timer.timeout.connect(self.check_if_paid_on_timer)
self.timer.start(5000) # Start the timer with a 5-second interval
# End dispute Accepted UI GUI
# Start: Dispute REJECED UI GUI
def update_ui_for_dispute_rejected(self):
# Clear the layout and display the new label with the data
# Clear all widgets from the vertical layout
for i in reversed(range(self.layout.count())):
item = self.layout.itemAt(i)
if item is not None:
widget = item.widget()
if widget is not None:
widget.deleteLater()
# Clear all widgets from the horizontal layout
for i in reversed(range(self.h_layout.count())):
item = self.h_layout.itemAt(i)
if item is not None:
widget = item.widget()
if widget is not None:
widget.deleteLater()
# Display the ID:
label_for_peer_to_peer_billing_id = QLabel(
f"Any billing issue? Your P2P ID is: {self.peer_to_peer_billing_id}")
label_for_peer_to_peer_billing_id.setWordWrap(True)
label_for_peer_to_peer_billing_id.setStyleSheet(self.label_style)
label_for_peer_to_peer_billing_id.setSizePolicy(
# Expanding vertical size policy
QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
self.layout.addWidget(label_for_peer_to_peer_billing_id)
# Create a button to Copy Paste ID:
self.copy_amount_button = QPushButton("Copy Your Billing ID")
# Set background and text color self.button.clicked.connect(self.show_selected)
self.copy_amount_button.setStyleSheet(
"font-size: 20px; padding: 20px; background-color: green; color: yellow;")
self.copy_amount_button.clicked.connect(self.copy_billing_id_function)
self.layout.addWidget(self.copy_amount_button)
# Status label:
self.update_sms_status_label = QLabel(
"I am so sorry to inform you that the automated system rejected your dispute. It's possible this is a technical error, please contact customer support with your Billing ID")
self.update_sms_status_label.setStyleSheet(
"background-color: white; color: black; font-size: 20px;")
self.update_sms_status_label.setWordWrap(True)
self.update_sms_status_label.setFixedWidth(800)
self.update_sms_status_label.setMaximumHeight(250)
self.layout.addWidget(self.update_sms_status_label)
# End: Dispute REJECED UI GUI
# Start: Zero Dispute. Finalize & End Peacefully. No Dispute. UI GUI
def update_ui_for_peaceful_finalized_acceptance(self):
# Clear the layout and display the new label with the data
# Clear all widgets from the vertical layout
for i in reversed(range(self.layout.count())):
item = self.layout.itemAt(i)
if item is not None:
widget = item.widget()
if widget is not None:
widget.deleteLater()
# Clear all widgets from the horizontal layout
for i in reversed(range(self.h_layout.count())):
item = self.h_layout.itemAt(i)
if item is not None:
widget = item.widget()
if widget is not None:
widget.deleteLater()
# Status label:
self.update_sms_status_label = QLabel(
"Thank you! This is complete. You can close the window.")
self.update_sms_status_label.setStyleSheet(self.active_style_box)
self.update_sms_status_label.setWordWrap(True)
self.update_sms_status_label.setFixedWidth(800)
self.update_sms_status_label.setMaximumHeight(250)
self.layout.addWidget(self.update_sms_status_label)
# End: Zero Dispute. Finalize & End Peacefully. No Dispute. UI GUI
# Start: Send REFUND CRYPTO address & Display result:
@asyncSlot()
async def gui_calls_send_crypto_address_for_refund(self):
self.timer.stop()
# Step 1: Run the async function
asyncio.create_task(
self.async_gui_calls_send_crypto_address_for_refund())
async def async_gui_calls_send_crypto_address_for_refund(self):
# Send this data to the Flask server
returned_data = await send_crypto_address_for_refund(self.peer_to_peer_billing_id, self.refund_crypto_text_box.text())
# DEBUG SECTION! uncomment to debug,
print(f"this is data: {returned_data}")
# Update the GUI with the response data
self.update_ui_after_sending_crypto_address(returned_data)
return returned_data
# Start: Display the Error Section:
def update_ui_after_sending_crypto_address(self, returned_data):
# Clear all widgets from the vertical layout
for i in reversed(range(self.layout.count())):
item = self.layout.itemAt(i)
if item is not None:
widget = item.widget()
if widget is not None:
widget.deleteLater()
# Clear all widgets from the horizontal layout
for i in reversed(range(self.h_layout.count())):
item = self.h_layout.itemAt(i)
if item is not None:
widget = item.widget()
if widget is not None:
widget.deleteLater()
for i in reversed(range(self.top_ribbon_h_layout.count())):
item = self.top_ribbon_h_layout.itemAt(i)
if item is not None:
widget = item.widget()
if widget is not None:
widget.deleteLater()
# This label gives the raw error message in a box:
self.update_status_label = QLabel(str(returned_data))
self.update_status_label.setStyleSheet(
"background-color: white; color: black; font-size: 25px;")
self.update_status_label.setWordWrap(True)
self.update_status_label.setFixedWidth(700)
self.update_status_label.setMaximumHeight(400)
self.layout.addWidget(self.update_status_label)
# End: Send REFUND CRYPTO address & Display result
def bring_trade_back_from_dead(self):
self.clear_the_main_page_ui()
message_for_user = f"The trade for {self.peer_to_peer_billing_id} is already finalized. Do you wish to pay 5 euros to restore it and get another code from the same service with the same number?"
self.label_for_api_fetch = QLabel(f"{message_for_user}")
self.label_for_api_fetch.setStyleSheet(self.active_style_box)
self.label_for_api_fetch.setWordWrap(True)
self.layout.addWidget(self.label_for_api_fetch)
# yes pay:
self.yes_restore_dead_session_button = QPushButton(
"Yes, Pay 5 Euros to Restore")
self.yes_restore_dead_session_button.setStyleSheet(
"font-size: 30px; padding: 10px; background-color: green; color: yellow;")
self.yes_restore_dead_session_button.clicked.connect(
self.yes_pay_to_restore_send)
self.layout.addWidget(self.yes_restore_dead_session_button)
# return to main page button:
self.return_to_the_main_page_button = QPushButton(
"Nevermind. Return to Main Page")
self.return_to_the_main_page_button.setStyleSheet(
"font-size: 30px; padding: 10px; background-color: red; color: black;")
self.return_to_the_main_page_button.clicked.connect(
self.update_ui_to_return_to_the_main_page)
self.layout.addWidget(self.return_to_the_main_page_button)
@asyncSlot() # Decorator to allow this method to be async
async def yes_pay_to_restore_send(self):
# Step 1: Run the async function
asyncio.create_task(self.restore_dead_trade_by_sending_to_flask())
# Step 2: Show dialog and hide button after a short delay
QTimer.singleShot(0, self.hide_restore_buttons)
# This button hides elements while being sent to the server, but these elements may already be hidden.
def hide_restore_buttons(self):
self.show_dialog()
# this is the regular restore flow:
try:
self.yes_restore_dead_session_button.setVisible(False)
self.return_to_the_main_page_button.setVisible(False)
self.label_for_api_fetch.setText(
"Please hold while we contact that SMS seller.")
except:
# objects have been deleted already:
pass
# this is the "lost address restore flow"
try:
self.get_new_address_button.setVisible(False)
except:
# objects have been deleted already:
pass
# Start: RESTORE Send data to Flask Section
# THIS IS STEP 1 OF RESTORE
async def restore_dead_trade_by_sending_to_flask(self):
# Send this data to the Flask server:
returned_data = await restore_an_already_finalized_number(self.peer_to_peer_billing_id, "restore")
print(f"this is data: {returned_data}")
are_we_checking_again = True
# We're checking if it returned an error or registered the user:
if 'code_status' in returned_data:
code_status = returned_data.get('code_status')
if code_status == "restore_requested" or code_status == "restore_initiated":
display_message_for_user = "Contacting the Seller to request a restoration, please remain patient. If the seller is busy with another buyer or asleep in their timezone, it may temporarily reject you. If so, then try again."
elif code_status == "restore_but_seller_busy":
display_message_for_user = "The Seller is busy. It might be sleeping time in his/her timezone, vacation time, or they are on a different gig. Please try back later."
are_we_checking_again = False
elif code_status == "restore_confirmed":
display_message_for_user = "Seller confirmed, one moment please, as you must pay"
else:
display_message_for_user = "One moment please"
try:
self.label_for_api_fetch.setText(f"{display_message_for_user}")
except: # incase it does not exist:
self.label_for_api_fetch = QLabel(
f"{display_message_for_user}")
self.label_for_api_fetch.setStyleSheet(self.active_style_box)
self.label_for_api_fetch.setWordWrap(True)
self.layout.addWidget(self.label_for_api_fetch)
if are_we_checking_again == True:
# We're doing a 5 second timer to check if the seller is ready:
self.timer = QTimer()
self.timer.timeout.connect(
self.step_two_of_restore_get_confirm)
self.timer.start(5000)
# Display Connection Errors:
elif 'error' in returned_data:
connection_error_is = returned_data['error']
self.update_ui_for_errors(connection_error_is)
elif 'message' in returned_data:
# Display Errors:
message = returned_data['message']
self.update_ui_for_errors(message)
else:
self.update_ui_for_errors(returned_data)
# Here we're on a repeat timer, checking the /restore endpoint if the guy is confirmed ready.
@asyncSlot()
async def step_two_of_restore_get_confirm(self):
# Step 1: Run the async function
asyncio.create_task(
self.on_timer_step_two_of_restore_dead_trade_by_sending_to_flask())
# THIS IS STEP 2 OF RESTORE
async def on_timer_step_two_of_restore_dead_trade_by_sending_to_flask(self):
# Send this data to the Flask server:
returned_data = await restore_an_already_finalized_number(self.peer_to_peer_billing_id, "is_restore_seller_ready")
print(returned_data)
if 'address' in returned_data:
print("We got an address")
# now this "restore flow" rejoins the main flow for new orders:
self.update_ui(returned_data)
elif 'code_status' in returned_data:
code_status = returned_data.get('code_status')
if code_status == "restore_confirmed":
self.timer.stop()
# We're now getting a crypto address:
self.get_restore_crypto_address()
elif code_status == "restore_but_seller_busy":
self.timer.stop()
display_message_for_user = "The Seller is busy. It might be sleeping time in his/her timezone, vacation time, or they are on a different gig. Please try back later."
self.label_for_api_fetch.setText(f"{display_message_for_user}")
# return to main page button:
self.return_to_the_main_page_button.setText(
"Fine. Return to Main Page")
self.return_to_the_main_page_button.setVisible(True)
# Display Connection Errors:
elif 'error' in returned_data:
connection_error_is = returned_data['error']
self.update_ui_for_errors(connection_error_is)
elif 'message' in returned_data:
message = returned_data['message']
# Display Errors:
self.update_ui_for_errors(message)
else:
returned_data_as_string = str(returned_data)
self.update_ui_for_errors(returned_data_as_string)
return returned_data
# End: RESTORE Send data to Flask Section
@asyncSlot() # Decorator to allow this method to be async
async def get_restore_crypto_address(self):
# Step 1: Run the async function
asyncio.create_task(self.get_crypto_addy_for_restore())
async def get_crypto_addy_for_restore(self):
# Send this data to the Flask server
returned_data = await restore_an_already_finalized_number(self.peer_to_peer_billing_id, "is_restore_seller_ready")
print(f"returned_data: {returned_data}")
if 'address' in returned_data:
print("We got an address")
# now this "restore flow" rejoins the main flow for new orders:
self.update_ui(self, returned_data)
else:
print("Error, we did not get a crypto address")
# this may not be needed
return returned_data
'''
def update_ui_to_pay_for_restore(self):
payment_address = returned_data_as_a_dictionary.get('address')
display_address = f"We got a payment_address: {payment_address}"
print(f"{display_address}")
self.label_for_api_fetch.setText(f"{display_address}")
# We're doing a 5 second timer to check if the code is ready from API:
self.timer = QTimer()
self.timer.timeout.connect(self.check_if_seller_paid_for_a_restore)
self.timer.start(5000)
@asyncSlot() # Decorator to allow this method to be async
async def check_if_seller_paid_for_a_restore(self):
# Step 1: Run the async function
asyncio.create_task(self.check_if_seller_paid_for_a_restore_function())
async def check_if_seller_paid_for_a_restore_function(self):
# Send this data to the Flask server
returned_data = await restore_an_already_finalized_number(self.peer_to_peer_billing_id, "is_restore_seller_ready")
# Update the GUI with the response data
print(f"returned_data: {returned_data}")
return returned_data
'''
if __name__ == "__main__":
app = QApplication(sys.argv)
# async loop for app so that it can fetch the API while it displays the intro text. Then go right into doing network calls with GUI changes,
loop = QEventLoop(app)
asyncio.set_event_loop(loop)
my_app = BuyerPeerPeerGUI()
my_app.show()
with loop:
sys.exit(loop.run_forever())