2468 lines
111 KiB
Python
Executable file
2468 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
|
|
import interact_with_rest_of_app.which_profile_is_being_used as which_profile_module
|
|
|
|
# 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())
|