diff options
Diffstat (limited to 'ui/src/main/res/layout')
17 files changed, 1843 insertions, 0 deletions
diff --git a/ui/src/main/res/layout/add_tunnels_bottom_sheet.xml b/ui/src/main/res/layout/add_tunnels_bottom_sheet.xml new file mode 100644 index 00000000..0ad1ef23 --- /dev/null +++ b/ui/src/main/res/layout/add_tunnels_bottom_sheet.xml @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright © 2017-2025 WireGuard LLC. All Rights Reserved. + ~ SPDX-License-Identifier: Apache-2.0 + --> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/root" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="@dimen/bottom_sheet_top_padding"> + + <com.google.android.material.button.MaterialButton + android:id="@+id/create_from_file" + style="@style/Widget.Material3.Button.TextButton.Icon" + android:layout_width="match_parent" + android:layout_height="@dimen/bottom_sheet_item_height" + android:layout_marginStart="@dimen/normal_margin" + android:layout_marginLeft="@dimen/normal_margin" + android:layout_marginEnd="@dimen/normal_margin" + android:layout_marginRight="@dimen/normal_margin" + android:nextFocusDown="@id/create_from_qrcode" + android:nextFocusForward="@id/create_from_qrcode" + android:text="@string/create_from_file" + android:textAlignment="viewStart" + android:textColor="?attr/colorOnSurface" + app:icon="@drawable/ic_action_open" + app:iconPadding="@dimen/bottom_sheet_icon_padding" + app:iconTint="?attr/colorSecondary" + app:layout_constraintBottom_toTopOf="@+id/create_from_qrcode" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="parent" + app:rippleColor="?attr/colorSecondary" /> + + <com.google.android.material.button.MaterialButton + android:id="@+id/create_from_qrcode" + style="@style/Widget.Material3.Button.TextButton.Icon" + android:layout_width="match_parent" + android:layout_height="@dimen/bottom_sheet_item_height" + android:layout_marginStart="@dimen/normal_margin" + android:layout_marginLeft="@dimen/normal_margin" + android:layout_marginEnd="@dimen/normal_margin" + android:layout_marginRight="@dimen/normal_margin" + android:nextFocusUp="@id/create_from_file" + android:nextFocusDown="@id/create_empty" + android:nextFocusForward="@id/create_empty" + android:text="@string/create_from_qr_code" + android:textAlignment="viewStart" + android:textColor="?attr/colorOnSurface" + app:icon="@drawable/ic_action_scan_qr_code" + app:iconPadding="@dimen/bottom_sheet_icon_padding" + app:iconTint="?attr/colorSecondary" + app:layout_constraintBottom_toBottomOf="@+id/create_empty" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/create_from_file" + app:rippleColor="?attr/colorSecondary" /> + + <com.google.android.material.button.MaterialButton + android:id="@+id/create_empty" + style="@style/Widget.Material3.Button.TextButton.Icon" + android:layout_width="match_parent" + android:layout_height="@dimen/bottom_sheet_item_height" + android:layout_marginStart="@dimen/normal_margin" + android:layout_marginLeft="@dimen/normal_margin" + android:layout_marginEnd="@dimen/normal_margin" + android:layout_marginRight="@dimen/normal_margin" + android:nextFocusUp="@id/create_from_qrcode" + android:text="@string/create_empty" + android:textAlignment="viewStart" + android:textColor="?attr/colorOnSurface" + app:icon="@drawable/ic_action_edit" + app:iconPadding="@dimen/bottom_sheet_icon_padding" + app:iconTint="?attr/colorSecondary" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/create_from_qrcode" + app:rippleColor="?attr/colorSecondary" /> + +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/ui/src/main/res/layout/app_list_dialog_fragment.xml b/ui/src/main/res/layout/app_list_dialog_fragment.xml new file mode 100644 index 00000000..98ee2b0f --- /dev/null +++ b/ui/src/main/res/layout/app_list_dialog_fragment.xml @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright © 2017-2025 WireGuard LLC. All Rights Reserved. + ~ SPDX-License-Identifier: Apache-2.0 + --> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> + + <data> + + <import type="android.view.View" /> + + <import type="com.wireguard.android.model.ApplicationData" /> + + <variable + name="fragment" + type="com.wireguard.android.fragment.AppListDialogFragment" /> + + <variable + name="appData" + type="com.wireguard.android.databinding.ObservableKeyedArrayList<String, ApplicationData>" /> + </data> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <com.google.android.material.tabs.TabLayout + android:id="@+id/tabs" + style="@style/Widget.Material3.TabLayout.OnSurface" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <com.google.android.material.tabs.TabItem + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/exclude_from_tunnel" /> + + <com.google.android.material.tabs.TabItem + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/include_in_tunnel" /> + </com.google.android.material.tabs.TabLayout> + + <FrameLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:minHeight="200dp"> + + <ProgressBar + android:id="@+id/progress_bar" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:indeterminate="true" + android:visibility="@{appData.isEmpty() ? View.VISIBLE : View.GONE}" + tools:visibility="gone" /> + + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/app_list" + android:layout_width="match_parent" + android:layout_height="match_parent" + app:items="@{appData}" + app:layout="@{@layout/app_list_item}" + tools:itemCount="10" + tools:listitem="@layout/app_list_item" /> + </FrameLayout> + </LinearLayout> +</layout> diff --git a/ui/src/main/res/layout/app_list_item.xml b/ui/src/main/res/layout/app_list_item.xml new file mode 100644 index 00000000..63a43ad8 --- /dev/null +++ b/ui/src/main/res/layout/app_list_item.xml @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright © 2017-2025 WireGuard LLC. All Rights Reserved. + ~ SPDX-License-Identifier: Apache-2.0 + --> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools"> + + <data> + + <import type="com.wireguard.android.model.ApplicationData" /> + + <variable + name="collection" + type="com.wireguard.android.databinding.ObservableKeyedArrayList<String, com.wireguard.android.model.ApplicationData>" /> + + <variable + name="key" + type="String" /> + + <variable + name="item" + type="com.wireguard.android.model.ApplicationData" /> + </data> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="@drawable/list_item_background" + android:gravity="center_vertical" + android:onClick="@{(view) -> item.setSelected(!item.selected)}" + android:orientation="horizontal" + android:paddingTop="8dp" + android:paddingBottom="8dp"> + + <ImageView + android:id="@+id/app_icon" + android:layout_width="32dp" + android:layout_height="32dp" + android:layout_marginStart="16dp" + android:src="@{item.icon}" + tools:src="@tools:sample/avatars" /> + + <TextView + android:id="@+id/app_name" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginStart="16dp" + android:layout_marginEnd="16dp" + android:layout_weight="1" + android:ellipsize="end" + android:maxLines="1" + android:text="@{key}" + android:textAppearance="?attr/textAppearanceBodyLarge" + tools:text="@tools:sample/full_names" /> + + <CheckBox + android:id="@+id/selected_checkbox" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:checked="@={item.selected}" + tools:checked="true" /> + + </LinearLayout> +</layout> diff --git a/ui/src/main/res/layout/config_naming_dialog_fragment.xml b/ui/src/main/res/layout/config_naming_dialog_fragment.xml new file mode 100644 index 00000000..32d556ab --- /dev/null +++ b/ui/src/main/res/layout/config_naming_dialog_fragment.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright © 2017-2025 WireGuard LLC. All Rights Reserved. + ~ SPDX-License-Identifier: Apache-2.0 + --> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <data> + + <import type="com.wireguard.android.widget.NameInputFilter" /> + </data> + + <FrameLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:padding="16dp"> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/tunnel_name_text_layout" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/tunnel_name_text" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="@string/tunnel_name" + android:imeOptions="actionDone" + android:inputType="textNoSuggestions|textVisiblePassword" + app:filter="@{NameInputFilter.newInstance()}"> + + <requestFocus /> + </com.google.android.material.textfield.TextInputEditText> + + </com.google.android.material.textfield.TextInputLayout> + + </FrameLayout> + +</layout> diff --git a/ui/src/main/res/layout/log_viewer_activity.xml b/ui/src/main/res/layout/log_viewer_activity.xml new file mode 100644 index 00000000..15925c08 --- /dev/null +++ b/ui/src/main/res/layout/log_viewer_activity.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright © 2017-2025 WireGuard LLC. All Rights Reserved. + ~ SPDX-License-Identifier: Apache-2.0 + --> + +<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:fitsSystemWindows="true"> + + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/recycler_view" + android:layout_width="match_parent" + android:layout_height="match_parent" + tools:itemCount="20" + tools:listitem="@layout/log_viewer_entry" /> + + <com.google.android.material.floatingactionbutton.FloatingActionButton + android:id="@+id/share_fab" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="bottom|end" + android:layout_margin="@dimen/fab_margin" + app:srcCompat="@drawable/ic_action_share_white" /> + +</androidx.coordinatorlayout.widget.CoordinatorLayout> diff --git a/ui/src/main/res/layout/log_viewer_entry.xml b/ui/src/main/res/layout/log_viewer_entry.xml new file mode 100644 index 00000000..3df73b35 --- /dev/null +++ b/ui/src/main/res/layout/log_viewer_entry.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright © 2017-2025 WireGuard LLC. All Rights Reserved. + ~ SPDX-License-Identifier: Apache-2.0 + --> + +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="6dp"> + + <com.google.android.material.textview.MaterialTextView + android:id="@+id/log_date" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="?attr/textAppearanceBodySmall" + android:textColor="?android:attr/textColorPrimary" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:text="Fri Mar 13 10:17:37 GMT+05:30 2020" /> + + <com.google.android.material.textview.MaterialTextView + android:id="@+id/log_msg" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="?attr/textAppearanceBodySmall" + android:textColor="?android:attr/textColorPrimary" + app:layout_constraintTop_toBottomOf="@id/log_date" + tools:text="FATAL EXCEPTION: Thread-2" /> + +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/ui/src/main/res/layout/main_activity.xml b/ui/src/main/res/layout/main_activity.xml new file mode 100644 index 00000000..ab3b7e63 --- /dev/null +++ b/ui/src/main/res/layout/main_activity.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright © 2017-2025 WireGuard LLC. All Rights Reserved. + ~ SPDX-License-Identifier: Apache-2.0 + --> +<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/main_activity_container" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:fitsSystemWindows="true" + tools:context=".activity.MainActivity"> + + <androidx.fragment.app.FragmentContainerView + android:id="@+id/list_detail_container" + android:name="com.wireguard.android.fragment.TunnelListFragment" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:tag="LIST" /> +</androidx.coordinatorlayout.widget.CoordinatorLayout> diff --git a/ui/src/main/res/layout/tunnel_creator_activity.xml b/ui/src/main/res/layout/tunnel_creator_activity.xml new file mode 100644 index 00000000..82273db2 --- /dev/null +++ b/ui/src/main/res/layout/tunnel_creator_activity.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright © 2017-2025 WireGuard LLC. All Rights Reserved. + ~ SPDX-License-Identifier: Apache-2.0 + --> +<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/main_activity_container" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:fitsSystemWindows="true" + tools:context=".activity.TunnelCreatorActivity"> + + <androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/editor_fragment" + android:name="com.wireguard.android.fragment.TunnelEditorFragment" + android:layout_width="match_parent" + android:layout_height="match_parent" /> +</androidx.coordinatorlayout.widget.CoordinatorLayout> diff --git a/ui/src/main/res/layout/tunnel_detail_fragment.xml b/ui/src/main/res/layout/tunnel_detail_fragment.xml new file mode 100644 index 00000000..aae3e397 --- /dev/null +++ b/ui/src/main/res/layout/tunnel_detail_fragment.xml @@ -0,0 +1,324 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright © 2017-2025 WireGuard LLC. All Rights Reserved. + ~ SPDX-License-Identifier: Apache-2.0 + --> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> + + <data> + + <import type="com.wireguard.android.backend.Tunnel.State" /> + + <import type="com.wireguard.android.util.ClipboardUtils" /> + + <variable + name="fragment" + type="com.wireguard.android.fragment.TunnelDetailFragment" /> + + <variable + name="tunnel" + type="com.wireguard.android.model.ObservableTunnel" /> + + <variable + name="config" + type="com.wireguard.config.Config" /> + </data> + + <ScrollView + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="?attr/colorSurface" + android:clickable="true" + android:focusable="true"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <com.google.android.material.card.MaterialCardView + android:id="@+id/tunnel_detail_card" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="8dp" + android:layout_marginTop="16dp" + android:layout_marginEnd="8dp" + android:layout_marginBottom="8dp" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <com.google.android.material.textview.MaterialTextView + android:id="@+id/interface_title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/interface_title" + android:textAppearance="?attr/textAppearanceTitleMedium" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <com.wireguard.android.widget.ToggleSwitch + android:id="@+id/tunnel_switch" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:nextFocusDown="@id/interface_name_text" + android:nextFocusForward="@id/interface_name_text" + app:checked="@{tunnel.state == State.UP}" + app:layout_constraintBaseline_toBottomOf="@+id/interface_title" + app:layout_constraintEnd_toEndOf="parent" + app:onBeforeCheckedChanged="@{fragment::setTunnelState}" /> + + <TextView + android:id="@+id/interface_name_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:labelFor="@+id/interface_name_text" + android:text="@string/name" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/interface_title" /> + + <TextView + android:id="@+id/interface_name_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:contentDescription="@string/name" + android:nextFocusUp="@id/tunnel_switch" + android:nextFocusDown="@id/public_key_text" + android:nextFocusForward="@id/public_key_text" + android:onClick="@{ClipboardUtils::copyTextView}" + android:text="@{tunnel.name}" + android:textAppearance="?attr/textAppearanceBodyLarge" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/interface_name_label" + tools:text="wg0" /> + + <TextView + android:id="@+id/public_key_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:labelFor="@+id/public_key_text" + android:text="@string/public_key" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/interface_name_text" /> + + <TextView + android:id="@+id/public_key_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:contentDescription="@string/public_key" + android:ellipsize="end" + android:maxLines="1" + android:nextFocusUp="@id/interface_name_text" + android:nextFocusDown="@id/addresses_text" + android:nextFocusForward="@id/addresses_text" + android:onClick="@{ClipboardUtils::copyTextView}" + android:singleLine="true" + android:text="@{config.interface.keyPair.publicKey.toBase64}" + android:textAppearance="?attr/textAppearanceBodyLarge" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/public_key_label" + tools:text="wOs2eguFEohqIZxlSJ1CAT9584tc6ejj9hfGFsoBVkA=" /> + + <TextView + android:id="@+id/addresses_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:labelFor="@+id/addresses_text" + android:text="@string/addresses" + android:visibility="@{config.interface.addresses.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/public_key_text" /> + + <TextView + android:id="@+id/addresses_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:contentDescription="@string/addresses" + android:nextFocusUp="@id/public_key_text" + android:nextFocusDown="@id/dns_servers_text" + android:nextFocusForward="@id/dns_servers_text" + android:onClick="@{ClipboardUtils::copyTextView}" + android:text="@{config.interface.addresses}" + android:textAppearance="?attr/textAppearanceBodyLarge" + android:visibility="@{config.interface.addresses.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/addresses_label" + tools:text="fc00:bbbb:bbbb:bb11::3:368b/128" /> + + <TextView + android:id="@+id/dns_servers_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:labelFor="@+id/dns_servers_text" + android:text="@string/dns_servers" + android:visibility="@{config.interface.dnsServers.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/addresses_text" /> + + <TextView + android:id="@+id/dns_servers_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:contentDescription="@string/dns_servers" + android:nextFocusUp="@id/addresses_text" + android:nextFocusDown="@id/dns_search_domains_text" + android:nextFocusForward="@id/dns_search_domains_text" + android:onClick="@{ClipboardUtils::copyTextView}" + android:text="@{config.interface.dnsServers}" + android:textAppearance="?attr/textAppearanceBodyLarge" + android:visibility="@{config.interface.dnsServers.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/dns_servers_label" + tools:text="8.8.8.8, 8.8.4.4" /> + + <TextView + android:id="@+id/dns_search_domains_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:labelFor="@+id/dns_search_domain_text" + android:text="@string/dns_search_domains" + android:visibility="@{config.interface.dnsSearchDomains.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/dns_servers_text" /> + + <TextView + android:id="@+id/dns_search_domains_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:contentDescription="@string/dns_search_domains" + android:nextFocusUp="@id/dns_servers_text" + android:nextFocusDown="@id/listen_port_text" + android:nextFocusForward="@id/listen_port_text" + android:onClick="@{ClipboardUtils::copyTextView}" + android:text="@{config.interface.dnsSearchDomains}" + android:textAppearance="?attr/textAppearanceBodyLarge" + android:visibility="@{config.interface.dnsSearchDomains.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/dns_search_domains_label" + tools:text="zx2c4.com" /> + + <TextView + android:id="@+id/listen_port_label" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:labelFor="@+id/listen_port_text" + android:text="@string/listen_port" + android:visibility="@{!config.interface.listenPort.isPresent() ? android.view.View.GONE : android.view.View.VISIBLE}" + app:layout_constraintEnd_toStartOf="@id/mtu_label" + app:layout_constraintHorizontal_weight="0.5" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/dns_search_domains_text" /> + + <TextView + android:id="@+id/listen_port_text" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:contentDescription="@string/listen_port" + android:nextFocusRight="@id/mtu_text" + android:nextFocusUp="@id/dns_search_domains_text" + android:nextFocusDown="@id/applications_text" + android:nextFocusForward="@id/mtu_text" + android:onClick="@{ClipboardUtils::copyTextView}" + android:text="@{config.interface.listenPort}" + android:textAppearance="?attr/textAppearanceBodyLarge" + android:visibility="@{!config.interface.listenPort.isPresent() ? android.view.View.GONE : android.view.View.VISIBLE}" + app:layout_constraintEnd_toStartOf="@id/mtu_label" + app:layout_constraintHorizontal_weight="0.5" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/listen_port_label" + tools:text="51820" /> + + <TextView + android:id="@+id/mtu_label" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:labelFor="@+id/mtu_text" + android:text="@string/mtu" + android:visibility="@{!config.interface.mtu.isPresent() ? android.view.View.GONE : android.view.View.VISIBLE}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_weight="0.5" + app:layout_constraintLeft_toRightOf="@id/listen_port_label" + app:layout_constraintStart_toEndOf="@id/listen_port_label" + app:layout_constraintTop_toBottomOf="@id/dns_search_domains_text" /> + + <TextView + android:id="@+id/mtu_text" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:contentDescription="@string/mtu" + android:nextFocusLeft="@id/listen_port_text" + android:nextFocusUp="@id/dns_servers_text" + android:nextFocusForward="@id/applications_text" + android:onClick="@{ClipboardUtils::copyTextView}" + android:text="@{config.interface.mtu}" + android:textAppearance="?attr/textAppearanceBodyLarge" + android:visibility="@{!config.interface.mtu.isPresent() ? android.view.View.GONE : android.view.View.VISIBLE}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_weight="0.5" + app:layout_constraintStart_toEndOf="@id/listen_port_label" + app:layout_constraintStart_toStartOf="@+id/mtu_label" + app:layout_constraintTop_toBottomOf="@+id/mtu_label" + tools:text="1500" /> + + <androidx.constraintlayout.widget.Barrier + android:id="@+id/listen_port_mtu_barrier" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:barrierDirection="bottom" + app:constraint_referenced_ids="listen_port_text,mtu_text" /> + + <TextView + android:id="@+id/applications_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:labelFor="@+id/applications_text" + android:text="@string/applications" + android:visibility="@{config.interface.includedApplications.isEmpty() && config.interface.excludedApplications.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/listen_port_mtu_barrier" /> + + <TextView + android:id="@+id/applications_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:contentDescription="@string/applications" + android:nextFocusUp="@id/mtu_text" + android:nextFocusDown="@id/peers_layout" + android:nextFocusForward="@id/peers_layout" + android:onClick="@{ClipboardUtils::copyTextView}" + android:text="@{config.interface.includedApplications.isEmpty() ? @plurals/n_excluded_applications(config.interface.excludedApplications.size(), config.interface.excludedApplications.size()) : @plurals/n_included_applications(config.interface.includedApplications.size(), config.interface.includedApplications.size())}" + android:textAppearance="?attr/textAppearanceBodyLarge" + android:visibility="@{config.interface.includedApplications.isEmpty() && config.interface.excludedApplications.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/applications_label" + tools:text="8 excluded" /> + </androidx.constraintlayout.widget.ConstraintLayout> + </com.google.android.material.card.MaterialCardView> + + <LinearLayout + android:id="@+id/peers_layout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:divider="@null" + android:orientation="vertical" + app:items="@{config.peers}" + app:layout="@{@layout/tunnel_detail_peer}" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/tunnel_detail_card" + tools:ignore="UselessLeaf" /> + </androidx.constraintlayout.widget.ConstraintLayout> + </ScrollView> +</layout> diff --git a/ui/src/main/res/layout/tunnel_detail_peer.xml b/ui/src/main/res/layout/tunnel_detail_peer.xml new file mode 100644 index 00000000..3cba9f03 --- /dev/null +++ b/ui/src/main/res/layout/tunnel_detail_peer.xml @@ -0,0 +1,230 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright © 2017-2025 WireGuard LLC. All Rights Reserved. + ~ SPDX-License-Identifier: Apache-2.0 + --> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> + + <data> + + <import type="com.wireguard.android.util.ClipboardUtils" /> + + <variable + name="item" + type="com.wireguard.config.Peer" /> + </data> + + <com.google.android.material.card.MaterialCardView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="8dp"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <com.google.android.material.textview.MaterialTextView + android:id="@+id/peer_title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/peer" + android:textAppearance="?attr/textAppearanceTitleMedium" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/public_key_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:labelFor="@+id/public_key_text" + android:text="@string/public_key" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/peer_title" /> + + <TextView + android:id="@+id/public_key_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:contentDescription="@string/public_key" + android:ellipsize="end" + android:maxLines="1" + android:nextFocusDown="@id/pre_shared_key_text" + android:nextFocusForward="@id/pre_shared_key_text" + android:onClick="@{ClipboardUtils::copyTextView}" + android:singleLine="true" + android:text="@{item.publicKey.toBase64}" + android:textAppearance="?attr/textAppearanceBodyLarge" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/public_key_label" + tools:text="wOs2eguFEohqIZxlSJ1CAT9584tc6ejj9hfGFsoBVkA=" /> + + <TextView + android:id="@+id/pre_shared_key_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:labelFor="@+id/pre_shared_key_text" + android:text="@string/pre_shared_key" + android:visibility="@{!item.preSharedKey.isPresent() ? android.view.View.GONE : android.view.View.VISIBLE}" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/public_key_text" /> + + <TextView + android:id="@+id/pre_shared_key_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:contentDescription="@string/pre_shared_key" + android:ellipsize="end" + android:maxLines="1" + android:nextFocusUp="@id/public_key_text" + android:nextFocusDown="@id/allowed_ips_text" + android:nextFocusForward="@id/allowed_ips_text" + android:singleLine="true" + android:text="@string/pre_shared_key_enabled" + android:textAppearance="?attr/textAppearanceBodyLarge" + android:visibility="@{!item.preSharedKey.isPresent() ? android.view.View.GONE : android.view.View.VISIBLE}" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/pre_shared_key_label" + tools:text="8VyS8W8XeMcBWfKp1GuG3/fZlnUQFkqMNbrdmZtVQIM=" /> + + <TextView + android:id="@+id/allowed_ips_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:labelFor="@+id/allowed_ips_text" + android:text="@string/allowed_ips" + android:visibility="@{item.allowedIps.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/pre_shared_key_text" /> + + <TextView + android:id="@+id/allowed_ips_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:contentDescription="@string/allowed_ips" + android:nextFocusUp="@id/pre_shared_key_text" + android:nextFocusDown="@id/endpoint_text" + android:nextFocusForward="@id/endpoint_text" + android:onClick="@{ClipboardUtils::copyTextView}" + android:text="@{item.allowedIps}" + android:textAppearance="?attr/textAppearanceBodyLarge" + android:visibility="@{item.allowedIps.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/allowed_ips_label" + tools:text="0.0.0.0/5, 8.0.0.0/7, 11.0.0.0/8, 12.0.0.0/6, 16.0.0.0/4, 32.0.0.0/3" /> + + <TextView + android:id="@+id/endpoint_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:labelFor="@+id/endpoint_text" + android:text="@string/endpoint" + android:visibility="@{!item.endpoint.isPresent() ? android.view.View.GONE : android.view.View.VISIBLE}" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/allowed_ips_text" /> + + <TextView + android:id="@+id/endpoint_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:contentDescription="@string/endpoint" + android:nextFocusUp="@id/allowed_ips_text" + android:nextFocusDown="@id/persistent_keepalive_text" + android:nextFocusForward="@id/persistent_keepalive_text" + android:onClick="@{ClipboardUtils::copyTextView}" + android:text="@{item.endpoint}" + android:textAppearance="?attr/textAppearanceBodyLarge" + android:visibility="@{!item.endpoint.isPresent() ? android.view.View.GONE : android.view.View.VISIBLE}" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/endpoint_label" + tools:text="192.168.0.1:51820" /> + + <TextView + android:id="@+id/persistent_keepalive_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:labelFor="@+id/persistent_keepalive_text" + android:text="@string/persistent_keepalive" + android:visibility="@{!item.persistentKeepalive.isPresent() ? android.view.View.GONE : android.view.View.VISIBLE}" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/endpoint_text" /> + + <TextView + android:id="@+id/persistent_keepalive_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:contentDescription="@string/persistent_keepalive" + android:nextFocusUp="@id/endpoint_text" + android:nextFocusDown="@id/transfer_text" + android:nextFocusForward="@id/transfer_text" + android:onClick="@{ClipboardUtils::copyTextView}" + android:text="@{@plurals/persistent_keepalive_seconds_unit(item.persistentKeepalive.orElse(0), item.persistentKeepalive.orElse(0))}" + android:textAppearance="?attr/textAppearanceBodyLarge" + android:visibility="@{!item.persistentKeepalive.isPresent() ? android.view.View.GONE : android.view.View.VISIBLE}" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/persistent_keepalive_label" + tools:text="every 3 seconds" /> + + <TextView + android:id="@+id/transfer_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@+id/persistent_keepalive_text" + android:layout_marginTop="8dp" + android:labelFor="@+id/transfer_text" + android:text="@string/transfer" + android:visibility="gone" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/persistent_keepalive_text" + tools:visibility="visible" /> + + <TextView + android:id="@+id/transfer_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@+id/transfer_label" + android:contentDescription="@string/transfer" + android:nextFocusUp="@id/persistent_keepalive_text" + android:onClick="@{ClipboardUtils::copyTextView}" + android:textAppearance="?attr/textAppearanceBodyLarge" + android:visibility="gone" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/transfer_label" + tools:text="1024 MB" + tools:visibility="visible" /> + + <TextView + android:id="@+id/latest_handshake_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@+id/transfer_text" + android:layout_marginTop="8dp" + android:labelFor="@+id/latest_handshake_text" + android:text="@string/latest_handshake" + android:visibility="gone" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/transfer_text" + tools:visibility="visible" /> + + <TextView + android:id="@+id/latest_handshake_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@+id/latest_handshake_label" + android:contentDescription="@string/latest_handshake" + android:nextFocusUp="@id/transfer_text" + android:onClick="@{ClipboardUtils::copyTextView}" + android:textAppearance="?attr/textAppearanceBodyLarge" + android:visibility="gone" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/latest_handshake_label" + tools:text="4 minutes, 27 seconds ago" + tools:visibility="visible" /> + </androidx.constraintlayout.widget.ConstraintLayout> + </com.google.android.material.card.MaterialCardView> +</layout> diff --git a/ui/src/main/res/layout/tunnel_editor_fragment.xml b/ui/src/main/res/layout/tunnel_editor_fragment.xml new file mode 100644 index 00000000..f25d2832 --- /dev/null +++ b/ui/src/main/res/layout/tunnel_editor_fragment.xml @@ -0,0 +1,295 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright © 2017-2025 WireGuard LLC. All Rights Reserved. + ~ SPDX-License-Identifier: Apache-2.0 + --> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> + + <data> + + <import type="com.wireguard.android.util.ClipboardUtils" /> + + <import type="com.wireguard.android.widget.KeyInputFilter" /> + + <import type="com.wireguard.android.widget.NameInputFilter" /> + + <variable + name="fragment" + type="com.wireguard.android.fragment.TunnelEditorFragment" /> + + <variable + name="config" + type="com.wireguard.android.viewmodel.ConfigProxy" /> + + <variable + name="name" + type="String" /> + </data> + + <androidx.coordinatorlayout.widget.CoordinatorLayout + android:id="@+id/main_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?attr/colorSurface"> + + <ScrollView + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <com.google.android.material.card.MaterialCardView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="8dp" + android:layout_marginTop="16dp" + android:layout_marginEnd="8dp" + android:layout_marginBottom="16dp"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <com.google.android.material.textview.MaterialTextView + android:id="@+id/interface_title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="8dp" + android:layout_marginTop="32dp" + android:text="@string/interface_title" + android:textAppearance="?attr/textAppearanceTitleMedium" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/interface_name_layout" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_margin="4dp" + android:hint="@string/name" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/interface_title"> + + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/interface_name_text" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:imeOptions="actionNext" + android:inputType="textNoSuggestions|textVisiblePassword" + android:nextFocusDown="@id/private_key_text" + android:nextFocusForward="@id/private_key_text" + android:text="@={name}" + app:filter="@{NameInputFilter.newInstance()}" /> + </com.google.android.material.textfield.TextInputLayout> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/private_key_text_layout" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_margin="4dp" + android:hint="@string/private_key" + app:endIconContentDescription="@string/generate_new_private_key" + app:endIconDrawable="@drawable/ic_action_generate" + app:endIconMode="custom" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/interface_name_layout"> + + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/private_key_text" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:imeOptions="actionNext" + android:inputType="textNoSuggestions|textPassword" + android:nextFocusUp="@id/interface_name_text" + android:nextFocusDown="@id/public_key_text" + android:nextFocusForward="@id/public_key_text" + android:onClick="@{fragment::onKeyClick}" + android:text="@={config.interface.privateKey}" + app:filter="@{KeyInputFilter.newInstance()}" + app:onFocusChange="@{fragment::onKeyFocusChange}" /> + </com.google.android.material.textfield.TextInputLayout> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/public_key_label_layout" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_margin="4dp" + android:hint="@string/public_key" + app:expandedHintEnabled="false" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/private_key_text_layout"> + + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/public_key_text" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:editable="false" + android:ellipsize="end" + android:focusable="false" + android:hint="@string/hint_generated" + android:imeOptions="actionNext" + android:nextFocusUp="@id/private_key_text" + android:nextFocusDown="@id/addresses_label_text" + android:nextFocusForward="@id/addresses_label_text" + android:onClick="@{ClipboardUtils::copyTextView}" + android:singleLine="true" + android:text="@{config.interface.publicKey}" /> + </com.google.android.material.textfield.TextInputLayout> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/addresses_label_layout" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_margin="4dp" + android:hint="@string/addresses" + app:layout_constraintEnd_toStartOf="@id/listen_port_label_layout" + app:layout_constraintHorizontal_chainStyle="spread" + app:layout_constraintHorizontal_weight="0.7" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/public_key_label_layout"> + + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/addresses_label_text" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:imeOptions="actionNext" + android:inputType="textNoSuggestions|textVisiblePassword" + android:nextFocusUp="@id/public_key_text" + android:nextFocusDown="@id/dns_servers_text" + android:nextFocusForward="@id/listen_port_text" + android:text="@={config.interface.addresses}" /> + </com.google.android.material.textfield.TextInputLayout> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/listen_port_label_layout" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_margin="4dp" + android:hint="@string/listen_port" + app:expandedHintEnabled="false" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_weight="0.3" + app:layout_constraintStart_toEndOf="@id/addresses_label_layout" + app:layout_constraintTop_toBottomOf="@id/public_key_label_layout"> + + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/listen_port_text" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="@string/hint_random" + android:imeOptions="actionNext" + android:inputType="number" + android:nextFocusUp="@id/public_key_text" + android:nextFocusDown="@id/mtu_text" + android:nextFocusForward="@id/dns_servers_text" + android:text="@={config.interface.listenPort}" + android:textAlignment="center" /> + </com.google.android.material.textfield.TextInputLayout> + + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/dns_servers_label_layout" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_margin="4dp" + android:hint="@string/dns_servers" + app:layout_constraintEnd_toStartOf="@id/mtu_label_layout" + app:layout_constraintHorizontal_chainStyle="spread" + app:layout_constraintHorizontal_weight="0.7" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/addresses_label_layout"> + + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/dns_servers_text" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:imeOptions="actionNext" + android:inputType="textNoSuggestions|textVisiblePassword" + android:nextFocusUp="@id/addresses_label_text" + android:nextFocusDown="@id/set_excluded_applications" + android:nextFocusForward="@id/mtu_text" + android:text="@={config.interface.dnsServers}" /> + </com.google.android.material.textfield.TextInputLayout> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/mtu_label_layout" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_margin="4dp" + android:hint="@string/mtu" + app:expandedHintEnabled="false" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_weight="0.3" + app:layout_constraintStart_toEndOf="@id/dns_servers_label_layout" + app:layout_constraintTop_toBottomOf="@id/addresses_label_layout"> + + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/mtu_text" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="@string/hint_automatic" + android:imeOptions="actionDone" + android:inputType="number" + android:nextFocusUp="@id/listen_port_text" + android:nextFocusDown="@id/set_excluded_applications" + android:nextFocusForward="@id/set_excluded_applications" + android:text="@={config.interface.mtu}" + android:textAlignment="center" /> + </com.google.android.material.textfield.TextInputLayout> + + <com.google.android.material.button.MaterialButton + android:id="@+id/set_excluded_applications" + style="@style/Widget.Material3.Button.TextButton" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_margin="4dp" + android:nextFocusUp="@id/dns_servers_text" + android:nextFocusDown="@id/peers_layout" + android:nextFocusForward="@id/peers_layout" + android:onClick="@{fragment::onRequestSetExcludedIncludedApplications}" + android:text="@{config.interface.includedApplications.size > 0 ? @plurals/set_included_applications(config.interface.includedApplications.size, config.interface.includedApplications.size) : config.interface.excludedApplications.size > 0 ? @plurals/set_excluded_applications(config.interface.excludedApplications.size, config.interface.excludedApplications.size) : @string/all_applications}" + android:textColor="?attr/colorSecondary" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/mtu_label_layout" + app:rippleColor="?attr/colorSecondary" + tools:text="4 excluded applications" /> + </androidx.constraintlayout.widget.ConstraintLayout> + </com.google.android.material.card.MaterialCardView> + + <LinearLayout + android:id="@+id/peers_layout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:divider="@null" + android:orientation="vertical" + app:fragment="@{fragment}" + app:items="@{config.peers}" + app:layout="@{@layout/tunnel_editor_peer}" + tools:ignore="UselessLeaf" /> + + <com.google.android.material.button.MaterialButton + android:id="@+id/add_peer_button" + style="@style/Widget.Material3.Button.TextButton" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom" + android:background="?attr/colorPrimaryDark" + android:gravity="center" + android:onClick="@{() -> config.addPeer()}" + android:text="@string/add_peer" + android:textColor="?attr/colorSecondary" + app:layout_anchorGravity="bottom" + app:rippleColor="?attr/colorSecondary" /> + </LinearLayout> + </ScrollView> + </androidx.coordinatorlayout.widget.CoordinatorLayout> +</layout> diff --git a/ui/src/main/res/layout/tunnel_editor_peer.xml b/ui/src/main/res/layout/tunnel_editor_peer.xml new file mode 100644 index 00000000..b879c0d9 --- /dev/null +++ b/ui/src/main/res/layout/tunnel_editor_peer.xml @@ -0,0 +1,203 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright © 2017-2025 WireGuard LLC. All Rights Reserved. + ~ SPDX-License-Identifier: Apache-2.0 + --> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <data> + + <import type="android.view.View" /> + + <import type="com.wireguard.android.widget.KeyInputFilter" /> + + <import type="com.wireguard.android.databinding.BindingAdapters" /> + + <variable + name="collection" + type="androidx.databinding.ObservableList<com.wireguard.android.viewmodel.PeerProxy>" /> + + <variable + name="item" + type="com.wireguard.android.viewmodel.PeerProxy" /> + + <variable + name="fragment" + type="com.wireguard.android.fragment.TunnelEditorFragment" /> + </data> + + <com.google.android.material.card.MaterialCardView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="8dp" + android:layout_marginTop="4dp" + android:layout_marginEnd="8dp" + android:layout_marginBottom="4dp"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <com.google.android.material.textview.MaterialTextView + android:id="@+id/peer_title" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_margin="8dp" + android:text="@string/peer" + android:textAppearance="?attr/textAppearanceTitleMedium" + app:layout_constraintBottom_toTopOf="@+id/public_key_label_layout" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <androidx.appcompat.widget.AppCompatImageButton + android:id="@+id/delete" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:background="@null" + android:nextFocusDown="@id/public_key_text" + android:nextFocusForward="@id/public_key_text" + android:onClick="@{() -> item.unbind()}" + android:padding="8dp" + android:src="@drawable/ic_action_delete" + app:layout_constraintBaseline_toBaselineOf="@id/peer_title" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="@id/peer_title" /> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/public_key_label_layout" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_margin="4dp" + android:hint="@string/public_key" + app:layout_constraintBottom_toTopOf="@+id/pre_shared_key_label_layout" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/peer_title"> + + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/public_key_text" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:imeOptions="actionNext" + android:inputType="textNoSuggestions|textVisiblePassword" + android:nextFocusUp="@id/delete" + android:nextFocusDown="@id/pre_shared_key_text" + android:nextFocusForward="@id/pre_shared_key_text" + android:text="@={item.publicKey}" + app:filter="@{KeyInputFilter.newInstance()}" /> + </com.google.android.material.textfield.TextInputLayout> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/pre_shared_key_label_layout" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_margin="4dp" + android:hint="@string/pre_shared_key" + app:expandedHintEnabled="false" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/public_key_label_layout"> + + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/pre_shared_key_text" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="@string/hint_optional" + android:imeOptions="actionNext" + android:inputType="textNoSuggestions|textPassword" + android:nextFocusUp="@id/public_key_text" + android:nextFocusDown="@id/persistent_keepalive_text" + android:nextFocusForward="@id/persistent_keepalive_text" + android:onClick="@{fragment::onKeyClick}" + android:text="@={item.preSharedKey}" + app:filter="@{KeyInputFilter.newInstance()}" + app:onFocusChange="@{fragment::onKeyFocusChange}" /> + </com.google.android.material.textfield.TextInputLayout> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/persistent_keepalive_label_layout" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_margin="4dp" + android:hint="@string/persistent_keepalive" + app:expandedHintEnabled="false" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/pre_shared_key_label_layout" + app:suffixText="@{@plurals/persistent_keepalive_seconds_suffix(BindingAdapters.tryParseInt(item.persistentKeepalive))}"> + + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/persistent_keepalive_text" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="@string/hint_optional_discouraged" + android:imeOptions="actionNext" + android:inputType="number" + android:nextFocusUp="@id/persistent_keepalive_text" + android:nextFocusDown="@id/endpoint_text" + android:nextFocusForward="@id/endpoint_text" + android:text="@={item.persistentKeepalive}" /> + </com.google.android.material.textfield.TextInputLayout> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/endpoint_label_layout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="4dp" + android:hint="@string/endpoint" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/persistent_keepalive_label_layout"> + + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/endpoint_text" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_alignParentStart="true" + android:imeOptions="actionNext" + android:inputType="textNoSuggestions|textVisiblePassword" + android:nextFocusUp="@id/persistent_keepalive_text" + android:nextFocusDown="@id/allowed_ips_text" + android:nextFocusForward="@id/allowed_ips_text" + android:text="@={item.endpoint}" /> + </com.google.android.material.textfield.TextInputLayout> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/allowed_ips_label_layout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="4dp" + android:hint="@string/allowed_ips" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/endpoint_label_layout"> + + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/allowed_ips_text" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_alignParentStart="true" + android:imeOptions="actionDone" + android:inputType="textNoSuggestions|textVisiblePassword" + android:nextFocusUp="@id/endpoint_text" + android:nextFocusDown="@id/selected_checkbox" + android:nextFocusForward="@id/selected_checkbox" + android:text="@={item.allowedIps}" /> + </com.google.android.material.textfield.TextInputLayout> + + <CheckBox + android:id="@+id/selected_checkbox" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_marginStart="4dp" + android:layout_marginTop="0dp" + android:checked="@={item.excludingPrivateIps}" + android:nextFocusDown="@id/add_peer_button" + android:nextFocusForward="@id/add_peer_button" + android:text="@string/exclude_private_ips" + android:visibility="@{item.ableToExcludePrivateIps ? View.VISIBLE : View.GONE}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toBottomOf="@id/allowed_ips_label_layout" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + </com.google.android.material.card.MaterialCardView> +</layout> diff --git a/ui/src/main/res/layout/tunnel_list_fragment.xml b/ui/src/main/res/layout/tunnel_list_fragment.xml new file mode 100644 index 00000000..17860783 --- /dev/null +++ b/ui/src/main/res/layout/tunnel_list_fragment.xml @@ -0,0 +1,85 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright © 2017-2025 WireGuard LLC. All Rights Reserved. + ~ SPDX-License-Identifier: Apache-2.0 + --> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> + + <data> + + <import type="com.wireguard.android.model.ObservableTunnel" /> + + <variable + name="fragment" + type="com.wireguard.android.fragment.TunnelListFragment" /> + + <variable + name="rowConfigurationHandler" + type="com.wireguard.android.databinding.ObservableKeyedRecyclerViewAdapter.RowConfigurationHandler" /> + + <variable + name="tunnels" + type="com.wireguard.android.databinding.ObservableKeyedArrayList<String, ObservableTunnel>" /> + </data> + + <androidx.coordinatorlayout.widget.CoordinatorLayout + android:id="@+id/main_container" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="?attr/colorSurface" + android:clipChildren="false"> + + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/tunnel_list" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:clipToPadding="false" + android:nextFocusDown="@id/create_fab" + android:nextFocusForward="@id/create_fab" + android:paddingBottom="@{@dimen/design_fab_size_normal * 1.1f}" + android:visibility="@{tunnels.size() > 0 ? android.view.View.VISIBLE : android.view.View.GONE}" + app:configurationHandler="@{rowConfigurationHandler}" + app:items="@{tunnels}" + app:layout="@{@layout/tunnel_list_item}" + tools:itemCount="12" + tools:listitem="@layout/tunnel_list_item" /> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:orientation="vertical" + android:visibility="@{tunnels.size() == 0 ? android.view.View.VISIBLE : android.view.View.GONE}" + tools:visibility="gone"> + + <androidx.appcompat.widget.AppCompatImageView + android:id="@+id/logo_placeholder" + android:layout_width="140dp" + android:layout_height="140dp" + android:layout_gravity="center" + android:layout_marginBottom="20dp" + android:alpha="0.3333333" + android:src="@mipmap/ic_launcher" /> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:layout_marginStart="@dimen/tunnel_list_placeholder_margin" + android:layout_marginEnd="@dimen/tunnel_list_placeholder_margin" + android:text="@string/tunnel_list_placeholder" + android:textSize="20sp" /> + </LinearLayout> + + <com.google.android.material.floatingactionbutton.FloatingActionButton + android:id="@+id/create_fab" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="bottom|end" + android:layout_margin="@dimen/fab_margin" + android:nextFocusUp="@id/tunnel_list" + app:srcCompat="@drawable/ic_action_add_white" /> + + </androidx.coordinatorlayout.widget.CoordinatorLayout> +</layout> diff --git a/ui/src/main/res/layout/tunnel_list_item.xml b/ui/src/main/res/layout/tunnel_list_item.xml new file mode 100644 index 00000000..2b5ecece --- /dev/null +++ b/ui/src/main/res/layout/tunnel_list_item.xml @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright © 2017-2025 WireGuard LLC. All Rights Reserved. + ~ SPDX-License-Identifier: Apache-2.0 + --> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> + + <data> + + <import type="com.wireguard.android.model.ObservableTunnel" /> + + <import type="com.wireguard.android.backend.Tunnel.State" /> + + <variable + name="collection" + type="com.wireguard.android.databinding.ObservableKeyedArrayList<String, ObservableTunnel>" /> + + <variable + name="key" + type="String" /> + + <variable + name="item" + type="com.wireguard.android.model.ObservableTunnel" /> + + <variable + name="fragment" + type="com.wireguard.android.fragment.TunnelListFragment" /> + </data> + + <com.wireguard.android.widget.MultiselectableRelativeLayout + android:id="@+id/tunnel_list_item" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="@drawable/list_item_background" + android:descendantFocusability="beforeDescendants" + android:focusable="true" + android:nextFocusRight="@+id/tunnel_switch" + android:paddingHorizontal="16dp" + android:paddingVertical="8dp"> + + <TextView + android:id="@+id/tunnel_name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentStart="true" + android:layout_centerVertical="true" + android:ellipsize="end" + android:maxLines="1" + android:text="@{key}" + android:textAppearance="?attr/textAppearanceBodyLarge" + tools:text="@sample/interface_names.json/names/names/name" /> + + <com.wireguard.android.widget.ToggleSwitch + android:id="@+id/tunnel_switch" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentEnd="true" + android:layout_centerVertical="true" + android:nextFocusLeft="@+id/tunnel_list_item" + app:checked="@{item.state == State.UP}" + app:onBeforeCheckedChanged="@{fragment::setTunnelState}" + tools:checked="@sample/interface_names.json/names/checked/checked" /> + </com.wireguard.android.widget.MultiselectableRelativeLayout> +</layout> diff --git a/ui/src/main/res/layout/tv_activity.xml b/ui/src/main/res/layout/tv_activity.xml new file mode 100644 index 00000000..f42808b3 --- /dev/null +++ b/ui/src/main/res/layout/tv_activity.xml @@ -0,0 +1,157 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright © 2017-2025 WireGuard LLC. All Rights Reserved. + ~ SPDX-License-Identifier: Apache-2.0 + --> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> + + <data> + + <import type="android.view.View" /> + + <import type="com.wireguard.android.model.ObservableTunnel" /> + + <import type="com.wireguard.android.activity.TvMainActivity.KeyedFile" /> + + <variable + name="isDeleting" + type="androidx.databinding.ObservableBoolean" /> + + <variable + name="files" + type="com.wireguard.android.databinding.ObservableKeyedArrayList<String, KeyedFile>" /> + + <variable + name="filesRoot" + type="androidx.databinding.ObservableField<String>" /> + + <variable + name="tunnels" + type="com.wireguard.android.databinding.ObservableKeyedArrayList<String, ObservableTunnel>" /> + + <variable + name="tunnelRowConfigurationHandler" + type="com.wireguard.android.databinding.ObservableKeyedRecyclerViewAdapter.RowConfigurationHandler" /> + + <variable + name="filesRowConfigurationHandler" + type="com.wireguard.android.databinding.ObservableKeyedRecyclerViewAdapter.RowConfigurationHandler" /> + </data> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <com.google.android.material.card.MaterialCardView + android:id="@+id/banner_logo" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:layout_marginStart="5dp" + android:layout_marginTop="5dp" + app:cardElevation="2dp" + app:contentPadding="0dp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + + <ImageView + android:layout_width="320dp" + android:layout_height="67dp" + android:contentDescription="@string/app_name" + android:scaleType="fitXY" + app:srcCompat="@drawable/tv_logo_banner" /> + + </com.google.android.material.card.MaterialCardView> + + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/tunnel_list" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_marginTop="16dp" + android:orientation="horizontal" + android:visibility="@{(tunnels.isEmpty || !filesRoot.isEmpty) ? View.GONE : View.VISIBLE}" + app:configurationHandler="@{tunnelRowConfigurationHandler}" + app:items="@{tunnels}" + app:layout="@{@layout/tv_tunnel_list_item}" + app:layoutManager="androidx.recyclerview.widget.GridLayoutManager" + app:layout_constraintBottom_toTopOf="@id/delete_button" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/banner_logo" + app:spanCount="3" + tools:itemCount="10" + tools:listitem="@layout/tv_tunnel_list_item" /> + + <TextView + android:id="@+id/files_root_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:layout_marginStart="8dp" + android:text="@{filesRoot}" + android:textAppearance="?attr/textAppearanceTitleLarge" + android:visibility="@{filesRoot.isEmpty ? View.GONE : View.VISIBLE}" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/banner_logo" + tools:visibility="gone" /> + + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/files_list" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_marginTop="16dp" + android:orientation="horizontal" + android:visibility="@{filesRoot.isEmpty ? View.GONE : View.VISIBLE}" + app:configurationHandler="@{filesRowConfigurationHandler}" + app:items="@{files}" + app:layout="@{@layout/tv_file_list_item}" + app:layoutManager="androidx.recyclerview.widget.GridLayoutManager" + app:layout_constraintBottom_toTopOf="@id/import_button" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/files_root_label" + app:spanCount="5" + tools:itemCount="10" + tools:listitem="@layout/tv_file_list_item" + tools:visibility="gone" /> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:text="@string/tv_add_tunnel_get_started" + android:textAppearance="?attr/textAppearanceHeadlineSmall" + android:visibility="@{(filesRoot.isEmpty && tunnels.isEmpty) ? View.VISIBLE : View.GONE}" + app:layout_constraintBottom_toTopOf="@id/delete_button" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/banner_logo" + tools:visibility="gone" /> + + <com.google.android.material.button.MaterialButton + android:id="@+id/import_button" + style="@style/Widget.Material3.Button.IconButton.Filled.Tonal" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="16dp" + android:minWidth="0dp" + android:visibility="@{isDeleting ? View.GONE : View.VISIBLE}" + app:icon="@{filesRoot.isEmpty ? @drawable/ic_action_add_white : @drawable/ic_arrow_back}" + app:iconPadding="0dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" /> + + <com.google.android.material.button.MaterialButton + android:id="@+id/delete_button" + style="@style/Widget.Material3.Button.IconButton.Filled.Tonal" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="16dp" + android:minWidth="0dp" + android:visibility="@{((tunnels.isEmpty && !isDeleting) || !filesRoot.isEmpty) ? View.GONE : View.VISIBLE}" + app:icon="@{isDeleting ? @drawable/ic_arrow_back : @drawable/ic_action_delete}" + app:iconPadding="0dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" /> + </androidx.constraintlayout.widget.ConstraintLayout> +</layout> diff --git a/ui/src/main/res/layout/tv_file_list_item.xml b/ui/src/main/res/layout/tv_file_list_item.xml new file mode 100644 index 00000000..84a3a433 --- /dev/null +++ b/ui/src/main/res/layout/tv_file_list_item.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright © 2017-2025 WireGuard LLC. All Rights Reserved. + ~ SPDX-License-Identifier: Apache-2.0 + --> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <data> + + <import type="com.wireguard.android.activity.TvMainActivity.KeyedFile" /> + + <variable + name="key" + type="String" /> + + <variable + name="item" + type="KeyedFile" /> + </data> + + <com.google.android.material.card.MaterialCardView + android:layout_width="320dp" + android:layout_height="50dp" + android:layout_margin="8dp" + android:layout_marginTop="4dp" + android:layout_marginBottom="0dp" + android:checkable="true" + android:focusable="true" + app:contentPadding="8dp"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <com.google.android.material.textview.MaterialTextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@{key}" + android:textAppearance="?attr/textAppearanceTitleLarge" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + + </com.google.android.material.card.MaterialCardView> + +</layout> diff --git a/ui/src/main/res/layout/tv_tunnel_list_item.xml b/ui/src/main/res/layout/tv_tunnel_list_item.xml new file mode 100644 index 00000000..08336e0c --- /dev/null +++ b/ui/src/main/res/layout/tv_tunnel_list_item.xml @@ -0,0 +1,85 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright © 2017-2025 WireGuard LLC. All Rights Reserved. + ~ SPDX-License-Identifier: Apache-2.0 + --> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> + + <data> + + <import type="android.view.View" /> + + <import type="com.wireguard.android.model.ObservableTunnel" /> + + <import type="com.wireguard.android.backend.Tunnel.State" /> + + <variable + name="isDeleting" + type="androidx.databinding.ObservableBoolean" /> + + <variable + name="isFocused" + type="androidx.databinding.ObservableBoolean" /> + + <variable + name="key" + type="String" /> + + <variable + name="item" + type="com.wireguard.android.model.ObservableTunnel" /> + </data> + + <com.wireguard.android.widget.TvCardView + android:layout_width="225dp" + android:layout_height="110dp" + android:layout_margin="8dp" + android:layout_marginTop="4dp" + android:layout_marginBottom="0dp" + android:backgroundTint="@color/tv_list_item_tint" + android:checkable="true" + android:focusable="true" + app:contentPadding="8dp" + app:isDeleting="@{isDeleting}" + app:isUp="@{item.state == State.UP}"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <com.google.android.material.textview.MaterialTextView + android:id="@+id/tunnel_name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@{item.name}" + android:textAppearance="?attr/textAppearanceTitleLarge" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:text="@sample/interface_names.json/names/names/name" /> + + <com.google.android.material.textview.MaterialTextView + android:id="@+id/tunnel_transfer" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="?attr/textAppearanceBodyLarge" + android:visibility="@{isDeleting ? View.GONE : View.VISIBLE}" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + tools:text="rx: 200 MB, tx: 100 MB" /> + + <com.google.android.material.textview.MaterialTextView + android:id="@+id/tunnel_delete" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/tv_delete" + android:visibility="@{(isDeleting && isFocused) ? View.VISIBLE : View.GONE}" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + tools:visibility="gone" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + + </com.wireguard.android.widget.TvCardView> + +</layout> |
