diff --git a/app/build.gradle b/app/build.gradle
index 7b69b5b72..86742443f 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -188,6 +188,8 @@ sonar {
}
dependencies {
+ implementation 'androidx.annotation:annotation:1.6.0'
+
/** Desugaring **/
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs_nio:2.0.3'
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 1127c55a4..09eb5d5f7 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -9,12 +9,11 @@
-
-
-
+
+
@@ -36,6 +35,16 @@
android:resizeableActivity="true"
android:theme="@style/OpeningTheme"
tools:ignore="AllowBackup">
+
+
+
-
-
-
-
-
-
+ android:exported="false" />
+
-
+
+
@@ -337,7 +342,7 @@
-
+
@@ -353,7 +358,6 @@
-
@@ -367,7 +371,6 @@
-
@@ -404,24 +407,21 @@
-
+
-
-
+ android:exported="false" />
-
+ android:value="true" />
-
+ android:value="true" />
-
+
+
\ No newline at end of file
diff --git a/app/src/main/java/org/schabi/newpipe/settings/AccountSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/AccountSettingsFragment.java
new file mode 100644
index 000000000..a7196fca9
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/settings/AccountSettingsFragment.java
@@ -0,0 +1,50 @@
+package org.schabi.newpipe.settings;
+
+import android.content.ActivityNotFoundException;
+import android.content.Intent;
+import android.os.Bundle;
+import android.widget.Toast;
+
+import androidx.preference.Preference;
+
+import org.schabi.newpipe.R;
+import org.schabi.newpipe.settings.profile.ManageAccounts;
+import org.schabi.newpipe.settings.profile.SignInActivity;
+
+public class AccountSettingsFragment extends BasePreferenceFragment {
+
+ @Override
+ public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) {
+ addPreferencesFromResourceRegistry();
+
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(final Preference preference) {
+ if (getString(R.string.sign_in).equals(preference.getKey())) {
+ try {
+ final Intent intent = new Intent(requireContext(), SignInActivity.class);
+ startActivity(intent);
+ } catch (final ActivityNotFoundException e) {
+ Toast.makeText(getActivity(), R.string.general_error, Toast.LENGTH_SHORT).show();
+ }
+ }
+// if (getString(R.string.sign_out).equals(preference.getKey())) {
+// try {
+// startActivity(new Intent(Settings.ACTION_CAPTIONING_SETTINGS));
+// } catch (final ActivityNotFoundException e) {
+// Toast.makeText(getActivity(), R.string.general_error, Toast.LENGTH_SHORT).show();
+// }
+// }
+ if (getString(R.string.manage_accounts).equals(preference.getKey())) {
+ try {
+ final Intent intent = new Intent(requireContext(), ManageAccounts.class);
+ startActivity(intent);
+ } catch (final ActivityNotFoundException e) {
+ Toast.makeText(getActivity(), R.string.general_error, Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ return super.onPreferenceTreeClick(preference);
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/settings/SettingsResourceRegistry.java b/app/src/main/java/org/schabi/newpipe/settings/SettingsResourceRegistry.java
index b3d0741bb..bf9d4afc0 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/SettingsResourceRegistry.java
+++ b/app/src/main/java/org/schabi/newpipe/settings/SettingsResourceRegistry.java
@@ -41,6 +41,7 @@ public final class SettingsResourceRegistry {
add(UpdateSettingsFragment.class, R.xml.update_settings);
add(VideoAudioSettingsFragment.class, R.xml.video_audio_settings);
add(ExoPlayerSettingsFragment.class, R.xml.exoplayer_settings);
+ add(AccountSettingsFragment.class, R.xml.account_settings);
}
private SettingRegistryEntry add(
diff --git a/app/src/main/java/org/schabi/newpipe/settings/profile/ManageAccounts.java b/app/src/main/java/org/schabi/newpipe/settings/profile/ManageAccounts.java
new file mode 100644
index 000000000..e694e1b1e
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/settings/profile/ManageAccounts.java
@@ -0,0 +1,49 @@
+package org.schabi.newpipe.settings.profile;
+
+import android.content.ActivityNotFoundException;
+import android.content.Intent;
+import android.os.Bundle;
+import android.widget.Toast;
+
+import androidx.preference.Preference;
+
+import org.schabi.newpipe.R;
+import org.schabi.newpipe.settings.BasePreferenceFragment;
+
+public class ManageAccounts extends BasePreferenceFragment {
+
+ @Override
+ public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) {
+ addPreferencesFromResourceRegistry();
+
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(final Preference preference) {
+ if (getString(R.string.sign_in).equals(preference.getKey())) {
+ try {
+ final Intent intent = new Intent(requireContext(), SignInActivity.class);
+ startActivity(intent);
+ } catch (final ActivityNotFoundException e) {
+ Toast.makeText(getActivity(), R.string.general_error, Toast.LENGTH_SHORT).show();
+ }
+ }
+// if (getString(R.string.sign_out).equals(preference.getKey())) {
+// try {
+// startActivity(new Intent(Settings.ACTION_CAPTIONING_SETTINGS));
+// } catch (final ActivityNotFoundException e) {
+// Toast.makeText(getActivity(), R.string.general_error, Toast.LENGTH_SHORT).show();
+// }
+// }
+ if (getString(R.string.manage_accounts).equals(preference.getKey())) {
+ try {
+ final Intent intent = new Intent(requireContext(), ManageAccounts.class);
+ startActivity(intent);
+ } catch (final ActivityNotFoundException e) {
+ Toast.makeText(getActivity(), R.string.general_error, Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ return super.onPreferenceTreeClick(preference);
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/settings/profile/SignInActivity.java b/app/src/main/java/org/schabi/newpipe/settings/profile/SignInActivity.java
new file mode 100644
index 000000000..852b1bf79
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/settings/profile/SignInActivity.java
@@ -0,0 +1,160 @@
+package org.schabi.newpipe.settings.profile;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.Toast;
+
+import androidx.appcompat.app.AppCompatActivity;
+
+import org.schabi.newpipe.MainActivity;
+import org.schabi.newpipe.R;
+
+import java.io.BufferedReader;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+
+public class SignInActivity extends AppCompatActivity {
+
+ private EditText etUsername;
+ private EditText etPassword;
+ private Button btLogin;
+ private Button btRegister;
+
+
+ @Override
+ protected void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_sign_in);
+ btLogin = findViewById(R.id.buttonLogin);
+ btRegister = findViewById(R.id.buttonRegister);
+ etUsername = findViewById(R.id.usernameEditText);
+ etPassword = findViewById(R.id.passwordEditText);
+
+ btLogin.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(final View v) {
+
+ final String enteredUsername = etUsername.getText().toString();
+ final String enteredPassword = etPassword.getText().toString();
+
+ if (authenticateUser(SignInActivity.this,
+ enteredUsername, enteredPassword)) {
+ // Successful
+ Toast.makeText(SignInActivity.this, "Login successful",
+ Toast.LENGTH_SHORT)
+ .show();
+ final Intent intent = new Intent(SignInActivity.this,
+ MainActivity.class);
+ intent.putExtra("username", enteredUsername);
+ startActivity(intent);
+ } else {
+ // Incorrect credentials
+ Toast.makeText(SignInActivity.this,
+ "Invalid username or password", Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ });
+
+ btRegister.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(final View view) {
+
+ final String username = etUsername.getText().toString().trim();
+ final String password = etPassword.getText().toString().trim();
+
+ // Check if username and password are not empty
+ if (!username.isEmpty() && !password.isEmpty()) {
+
+ final boolean registrationSuccessful = registerUser(username, password);
+
+ if (registrationSuccessful) {
+
+ Toast.makeText(getApplicationContext(), "Registration successful",
+ Toast.LENGTH_SHORT).show();
+ } else {
+
+ Toast.makeText(getApplicationContext(), "Registration failed",
+ Toast.LENGTH_SHORT).show();
+ }
+ } else {
+
+ Toast.makeText(getApplicationContext(),
+ "Please enter both username and password",
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ });
+ }
+
+ private boolean authenticateUser(final Context context,
+ final String username, final String password) {
+ try {
+ final InputStream inputStream = context.getResources()
+ .openRawResource(R.raw.credentials);
+ final BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
+ String line;
+ System.out.println(inputStream);
+ while ((line = reader.readLine()) != null) {
+ line = line.replace("*", "").trim();
+ final String[] fields = line.split("\\|\\|");
+
+ boolean usernameCorrect = false;
+ boolean passwordCorrect = false;
+
+ for (final String field : fields) {
+ final String[] keyValue = field.split("=");
+ if (keyValue.length == 2) {
+ final String key = keyValue[0].trim();
+ final String value = keyValue[1].trim();
+
+ if (key.equals("username") && value.equals(username)) {
+ usernameCorrect = true;
+ } else if (key.equals("password") && value.equals(password)) {
+ passwordCorrect = true;
+ }
+ }
+ }
+
+ if (usernameCorrect && passwordCorrect) {
+ return true;
+ }
+ }
+
+ reader.close();
+ } catch (final IOException e) {
+ e.printStackTrace();
+ }
+
+ return false;
+ }
+
+ private boolean registerUser(final String username, final String password) {
+ try {
+
+ final FileOutputStream fos = openFileOutput("credentials.txt",
+ Context.MODE_APPEND);
+
+
+ final String newCredentials = "*username=" + username
+ + "||password=" + password + "*\n";
+
+ fos.write(newCredentials.getBytes());
+
+ fos.close();
+
+ return true;
+ } catch (final IOException e) {
+ e.printStackTrace();
+
+ return false;
+ }
+ }
+}
diff --git a/app/src/main/res/layout-w1240dp/activity_login.xml b/app/src/main/res/layout-w1240dp/activity_login.xml
new file mode 100644
index 000000000..368db092f
--- /dev/null
+++ b/app/src/main/res/layout-w1240dp/activity_login.xml
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout-w936dp/activity_login.xml b/app/src/main/res/layout-w936dp/activity_login.xml
new file mode 100644
index 000000000..442430671
--- /dev/null
+++ b/app/src/main/res/layout-w936dp/activity_login.xml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml
new file mode 100644
index 000000000..368db092f
--- /dev/null
+++ b/app/src/main/res/layout/activity_login.xml
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_sign_in.xml b/app/src/main/res/layout/activity_sign_in.xml
new file mode 100644
index 000000000..eb6df6120
--- /dev/null
+++ b/app/src/main/res/layout/activity_sign_in.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/raw/credentials b/app/src/main/res/raw/credentials
new file mode 100644
index 000000000..fcbbf721f
--- /dev/null
+++ b/app/src/main/res/raw/credentials
@@ -0,0 +1,2 @@
+*username=Account1||password=test1*
+*username=Account2||password=test2*
diff --git a/app/src/main/res/raw/data b/app/src/main/res/raw/data
new file mode 100644
index 000000000..351390a1a
--- /dev/null
+++ b/app/src/main/res/raw/data
@@ -0,0 +1,2 @@
+*username=Account1||www.google.com||www.yahoo.com*
+*username=Account2||www.bing.com||www.duckduckgo.com*
\ No newline at end of file
diff --git a/app/src/main/res/values-land/dimens.xml b/app/src/main/res/values-land/dimens.xml
index 46244b3c9..776eb95c6 100644
--- a/app/src/main/res/values-land/dimens.xml
+++ b/app/src/main/res/values-land/dimens.xml
@@ -55,4 +55,5 @@
14sp
13dp
+ 48dp
diff --git a/app/src/main/res/values-w1240dp/dimens.xml b/app/src/main/res/values-w1240dp/dimens.xml
new file mode 100644
index 000000000..7e0651166
--- /dev/null
+++ b/app/src/main/res/values-w1240dp/dimens.xml
@@ -0,0 +1,3 @@
+
+ 200dp
+
\ No newline at end of file
diff --git a/app/src/main/res/values-w600dp/dimens.xml b/app/src/main/res/values-w600dp/dimens.xml
new file mode 100644
index 000000000..5f681ae11
--- /dev/null
+++ b/app/src/main/res/values-w600dp/dimens.xml
@@ -0,0 +1,3 @@
+
+ 48dp
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 435e9a382..b36e8ea13 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -551,6 +551,11 @@
Checking frequency
Required network connection
Any network
+
+ Create account
+ Sign in another account
+ Sign out
+ Manage accounts
Updates
Show a notification to prompt app update when a new version is available
@@ -740,6 +745,7 @@
This content is only available to users who have paid, so it cannot be streamed or downloaded by NewPipe.
Featured
Radio
+ Accounts
Automatic (device theme)
Select your favorite night theme — %s
You can select your favorite night theme below
@@ -838,4 +844,13 @@
Share URL list
- %1$s: %2$s
%1$s\n%2$s
+ LoginActivity
+ Email
+ Password
+ Sign in or register
+ Sign in
+ "Welcome !"
+ Not a valid username
+ Password must be >5 characters
+ "Login failed"
diff --git a/app/src/main/res/xml/account_settings.xml b/app/src/main/res/xml/account_settings.xml
new file mode 100644
index 000000000..34d58467b
--- /dev/null
+++ b/app/src/main/res/xml/account_settings.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/activity_manage_accounts.xml b/app/src/main/res/xml/activity_manage_accounts.xml
new file mode 100644
index 000000000..74fa9568f
--- /dev/null
+++ b/app/src/main/res/xml/activity_manage_accounts.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/main_settings.xml b/app/src/main/res/xml/main_settings.xml
index 1b1c17e85..074c70063 100644
--- a/app/src/main/res/xml/main_settings.xml
+++ b/app/src/main/res/xml/main_settings.xml
@@ -47,10 +47,17 @@
android:title="@string/settings_category_updates_title"
app:iconSpaceReserved="false" />
+
+
+
diff --git a/gradle.properties b/gradle.properties
index 7b138b24e..0508b1253 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,7 +1,20 @@
+## For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+#
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+# Default value: -Xmx1024m -XX:MaxPermSize=256m
+# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
+#
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+#Thu Oct 12 02:17:31 AEDT 2023
android.defaults.buildfeatures.buildconfig=true
android.enableJetifier=false
android.nonFinalResIds=false
android.nonTransitiveRClass=false
android.useAndroidX=true
-org.gradle.jvmargs=-Xmx2048M --add-opens jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED
+org.gradle.jvmargs=-Xmx2048M -Dkotlin.daemon.jvm.options\="-Xmx2048M" --add-opens jdk.compiler/com.sun.tools.javac.model\=ALL-UNNAMED
systemProp.file.encoding=utf-8