Polycentric fixes, missing sync files

This commit is contained in:
Kelvin 2024-09-30 18:28:43 +02:00
parent fcbab10434
commit 7f26ac00b1
13 changed files with 196 additions and 49 deletions

View file

@ -3,6 +3,7 @@ package com.futo.platformplayer.activities
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.widget.EditText
import android.widget.ImageButton
import android.widget.LinearLayout
@ -17,6 +18,7 @@ import com.futo.platformplayer.polycentric.PolycentricStorage
import com.futo.platformplayer.setNavigationBarColorAndIcons
import com.futo.platformplayer.states.StateApp
import com.futo.platformplayer.states.StatePolycentric
import com.futo.platformplayer.views.LoaderView
import com.futo.polycentric.core.ProcessHandle
import com.futo.polycentric.core.Store
import kotlinx.coroutines.Dispatchers
@ -27,6 +29,7 @@ class PolycentricCreateProfileActivity : AppCompatActivity() {
private lateinit var _buttonHelp: ImageButton;
private lateinit var _profileName: EditText;
private lateinit var _buttonCreate: LinearLayout;
private lateinit var _loader: LoaderView;
private val TAG = "PolycentricCreateProfileActivity";
private var _creating = false;
@ -43,6 +46,7 @@ class PolycentricCreateProfileActivity : AppCompatActivity() {
_buttonHelp = findViewById(R.id.button_help);
_profileName = findViewById(R.id.edit_profile_name);
_buttonCreate = findViewById(R.id.button_create_profile);
_loader = findViewById(R.id.loader);
findViewById<ImageButton>(R.id.button_back).setOnClickListener {
finish();
};
@ -65,35 +69,49 @@ class PolycentricCreateProfileActivity : AppCompatActivity() {
return@setOnClickListener;
}
_profileName.isEnabled = false;
_buttonCreate.visibility = View.GONE;
_loader.start();
_loader.visibility = View.VISIBLE;
lifecycleScope.launch(Dispatchers.IO) {
val processHandle: ProcessHandle;
try {
processHandle = ProcessHandle.create();
Store.instance.addProcessSecret(processHandle.processSecret);
try {
PolycentricStorage.instance.addProcessSecret(processHandle.processSecret)
processHandle = ProcessHandle.create();
Store.instance.addProcessSecret(processHandle.processSecret);
try {
PolycentricStorage.instance.addProcessSecret(processHandle.processSecret)
} catch (e: Throwable) {
Logger.e(TAG, "Failed to save process secret to secret storage.", e)
}
processHandle.addServer(PolycentricCache.SERVER);
processHandle.setUsername(username);
StatePolycentric.instance.setProcessHandle(processHandle);
} catch (e: Throwable) {
Logger.e(TAG, "Failed to save process secret to secret storage.", e)
Logger.e(TAG, getString(R.string.failed_to_create_profile), e);
return@launch;
} finally {
_creating = false;
}
processHandle.addServer(PolycentricCache.SERVER);
processHandle.setUsername(username);
StatePolycentric.instance.setProcessHandle(processHandle);
} catch (e: Throwable) {
Logger.e(TAG, getString(R.string.failed_to_create_profile), e);
return@launch;
} finally {
_creating = false;
try {
Logger.i(TAG, "Started backfill");
processHandle.fullyBackfillServersAnnounceExceptions();
Logger.i(TAG, "Finished backfill");
} catch (e: Throwable) {
Logger.e(TAG, getString(R.string.failed_to_fully_backfill_servers), e);
}
}
try {
Logger.i(TAG, "Started backfill");
processHandle.fullyBackfillServersAnnounceExceptions();
Logger.i(TAG, "Finished backfill");
} catch (e: Throwable) {
Logger.e(TAG, getString(R.string.failed_to_fully_backfill_servers), e);
finally {
withContext(Dispatchers.Main) {
_profileName.isEnabled = true;
_buttonCreate.visibility = View.VISIBLE;
_loader.stop();
_loader.visibility = View.GONE;
}
}
withContext(Dispatchers.Main) {

View file

@ -8,6 +8,7 @@ import android.os.Bundle
import android.util.TypedValue
import android.widget.ImageButton
import android.widget.LinearLayout
import android.widget.ScrollView
import androidx.appcompat.app.AppCompatActivity
import com.bumptech.glide.Glide
import com.bumptech.glide.request.target.CustomTarget
@ -28,6 +29,7 @@ class PolycentricHomeActivity : AppCompatActivity() {
private lateinit var _buttonNewProfile: BigButton;
private lateinit var _buttonImportProfile: BigButton;
private lateinit var _layoutButtons: LinearLayout;
private lateinit var _scroll: ScrollView;
override fun attachBaseContext(newBase: Context?) {
super.attachBaseContext(StateApp.instance.getLocaleContext(newBase))
@ -42,6 +44,7 @@ class PolycentricHomeActivity : AppCompatActivity() {
_buttonNewProfile = findViewById(R.id.button_new_profile);
_buttonImportProfile = findViewById(R.id.button_import_profile);
_layoutButtons = findViewById(R.id.layout_buttons);
_scroll = findViewById(R.id.scroll);
findViewById<ImageButton>(R.id.button_back).setOnClickListener {
finish();
};
@ -78,6 +81,7 @@ class PolycentricHomeActivity : AppCompatActivity() {
_layoutButtons.addView(profileButton, 0);
}
_scroll.invalidate();
_buttonHelp.setOnClickListener {
startActivity(Intent(this, PolycentricWhyActivity::class.java));

View file

@ -25,6 +25,7 @@ import com.futo.platformplayer.fullyBackfillServersAnnounceExceptions
import com.futo.platformplayer.images.GlideHelper.Companion.crossfade
import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.polycentric.PolycentricCache
import com.futo.platformplayer.polycentric.PolycentricStorage
import com.futo.platformplayer.selectBestImage
import com.futo.platformplayer.setNavigationBarColorAndIcons
import com.futo.platformplayer.states.StateApp
@ -33,6 +34,7 @@ import com.futo.platformplayer.views.buttons.BigButton
import com.futo.platformplayer.views.overlays.LoaderOverlay
import com.futo.polycentric.core.Store
import com.futo.polycentric.core.SystemState
import com.futo.polycentric.core.systemToURLInfoSystemLinkUrl
import com.futo.polycentric.core.toBase64Url
import com.futo.polycentric.core.toURLInfoSystemLinkUrl
import com.github.dhaval2404.imagepicker.ImagePicker
@ -47,6 +49,7 @@ class PolycentricProfileActivity : AppCompatActivity() {
private lateinit var _buttonHelp: ImageButton;
private lateinit var _editName: EditText;
private lateinit var _buttonExport: BigButton;
private lateinit var _buttonOpenHarborProfile: BigButton;
private lateinit var _buttonLogout: BigButton;
private lateinit var _buttonDelete: BigButton;
private lateinit var _username: String;
@ -68,6 +71,7 @@ class PolycentricProfileActivity : AppCompatActivity() {
_imagePolycentric = findViewById(R.id.image_polycentric);
_editName = findViewById(R.id.edit_profile_name);
_buttonExport = findViewById(R.id.button_export);
_buttonOpenHarborProfile = findViewById(R.id.button_open_harbor_profile);
_buttonLogout = findViewById(R.id.button_logout);
_buttonDelete = findViewById(R.id.button_delete);
_loaderOverlay = findViewById(R.id.loader_overlay);
@ -92,6 +96,16 @@ class PolycentricProfileActivity : AppCompatActivity() {
startActivity(Intent(this, PolycentricBackupActivity::class.java));
};
_buttonOpenHarborProfile.onClick.subscribe {
val processHandle = StatePolycentric.instance.processHandle!!;
processHandle?.let {
val systemState = SystemState.fromStorageTypeSystemState(Store.instance.getSystemState(it.system));
val url = it.system.systemToURLInfoSystemLinkUrl(systemState.servers.asIterable());
val navUrl = "https://harbor.social/" + url.substring("polycentric://".length)
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(navUrl)))
}
}
_buttonLogout.onClick.subscribe {
StatePolycentric.instance.setProcessHandle(null);
startActivity(Intent(this, PolycentricHomeActivity::class.java));
@ -108,6 +122,7 @@ class PolycentricProfileActivity : AppCompatActivity() {
StatePolycentric.instance.setProcessHandle(null);
Store.instance.removeProcessSecret(processHandle.system);
PolycentricStorage.instance.removeProcessSecret(processHandle.system);
startActivity(Intent(this, PolycentricHomeActivity::class.java));
finish();
});

View file

@ -133,6 +133,10 @@ class ChannelAboutFragment : Fragment, IChannelTabFragment {
Logger.w(TAG, "Failed to parse claim=$c", e)
}
}
if(!map.containsKey("Harbor"))
this.context?.let {
map.set("Harbor", polycentricProfile.getHarborUrl(it));
}
if (map.isNotEmpty())
setLinks(map, if (polycentricProfile.systemState.username.isNotBlank()) polycentricProfile.systemState.username else _lastChannel?.name ?: "")

View file

@ -1,7 +1,10 @@
package com.futo.platformplayer.fragment.mainactivity.main
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.graphics.drawable.Animatable
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@ -12,6 +15,7 @@ import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.appcompat.widget.AppCompatImageView
import androidx.core.content.ContextCompat.startActivity
import androidx.lifecycle.lifecycleScope
import androidx.viewpager2.widget.ViewPager2
import com.bumptech.glide.Glide
@ -52,7 +56,9 @@ import com.futo.platformplayer.views.overlays.slideup.SlideUpMenuOverlay
import com.futo.platformplayer.views.subscriptions.SubscribeButton
import com.futo.polycentric.core.OwnedClaim
import com.futo.polycentric.core.PublicKey
import com.futo.polycentric.core.Store
import com.futo.polycentric.core.SystemState
import com.futo.polycentric.core.systemToURLInfoSystemLinkUrl
import com.futo.polycentric.core.toURLInfoSystemLinkUrl
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
@ -64,7 +70,13 @@ import kotlinx.serialization.Serializable
@Serializable
data class PolycentricProfile(
val system: PublicKey, val systemState: SystemState, val ownedClaims: List<OwnedClaim>
)
) {
fun getHarborUrl(context: Context): String{
val systemState = SystemState.fromStorageTypeSystemState(Store.instance.getSystemState(system));
val url = system.systemToURLInfoSystemLinkUrl(systemState.servers.asIterable());
return "https://harbor.social/" + url.substring("polycentric://".length);
}
}
class ChannelFragment : MainFragment() {
override val isMainView: Boolean = true

View file

@ -5,6 +5,7 @@ import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.stores.FragmentedStorage
import com.futo.platformplayer.stores.StringArrayStorage
import com.futo.polycentric.core.ProcessSecret
import com.futo.polycentric.core.PublicKey
import com.futo.polycentric.core.base64ToByteArray
import com.futo.polycentric.core.toBase64
import userpackage.Protocol
@ -29,6 +30,18 @@ class PolycentricStorage {
return processSecrets
}
fun removeProcessSecret(publicKey: PublicKey) {
for(p in _processSecrets.getAllValues()){
try {
val key = ProcessSecret.fromProto(Protocol.StorageTypeProcessSecret.parseFrom(GEncryptionProviderV1.instance.decrypt(p.base64ToByteArray())));
if(key.system.publicKey.equals(publicKey))
_processSecrets.remove(p);
} catch (e: Throwable) {
Logger.i(TAG, "Failed to decrypt process secret", e);
}
}
}
companion object {
val TAG = "PolycentricStorage";
private var _instance : PolycentricStorage? = null;

View file

@ -0,0 +1,11 @@
package com.futo.platformplayer.sync.internal
class GJSyncOpcodes {
companion object {
val sendToDevices: UByte = 101.toUByte();
val syncExport: UByte = 201.toUByte();
val syncSubscriptions: UByte = 202.toUByte();
val syncHistory: UByte = 203.toUByte();
}
}

View file

@ -0,0 +1,9 @@
package com.futo.platformplayer.sync.models
import kotlinx.serialization.Serializable
@Serializable
class SendToDevicePackage(
var url: String,
var position: Int = 0
)

View file

@ -0,0 +1,12 @@
package com.futo.platformplayer.sync.models
import com.futo.platformplayer.models.Subscription
import kotlinx.serialization.Serializable
import java.time.OffsetDateTime
import java.util.Dictionary
@Serializable
class SyncSubscriptionsPackage(
var subscriptions: List<Subscription>,
var subscriptionRemovals: Map<String, Long>
)

View file

@ -42,11 +42,17 @@ class PlatformLinkView : LinearLayout {
}
fun setPlatform(name: String, url: String) {
val icon = StatePlatform.instance.getClientOrNullByUrl(url)?.icon;
if (icon != null) {
icon.setImageView(_imagePlatform, R.drawable.ic_web_white);
} else {
_imagePlatform.setImageResource(R.drawable.ic_web_white);
if(url.startsWith("https://harbor.social")) {
_imagePlatform.setImageResource(R.drawable.neopass);
}
else {
val icon = StatePlatform.instance.getClientOrNullByUrl(url)?.icon;
if (icon != null) {
icon.setImageView(_imagePlatform, R.drawable.ic_web_white);
} else {
_imagePlatform.setImageResource(R.drawable.ic_web_white);
}
}
_textName.text = name;

View file

@ -92,5 +92,13 @@
android:textSize="16dp"
android:text="@string/create_profile" />
</LinearLayout>
<com.futo.platformplayer.views.LoaderView
android:id="@+id/loader"
android:layout_width="match_parent"
android:layout_height="50dp"
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@id/button_create_profile"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -45,33 +45,43 @@
app:layout_constraintLeft_toLeftOf="@id/image_polycentric"
app:layout_constraintRight_toRightOf="@id/image_polycentric" />
<LinearLayout
android:id="@+id/layout_buttons"
<ScrollView
android:id="@+id/scroll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="0px"
android:layout_marginTop="10dp"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:layout_marginTop="30dp"
app:layout_constraintTop_toBottomOf="@id/text_polycentric"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent">
app:layout_constraintTop_toBottomOf="@id/text_polycentric">
<com.futo.platformplayer.views.buttons.BigButton
android:id="@+id/button_new_profile"
<LinearLayout
android:id="@+id/layout_buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:buttonText="@string/new_profile"
app:buttonSubText="@string/generate_a_new_identity"
app:buttonIcon="@drawable/ic_person_add" />
android:paddingTop="20dp"
android:paddingBottom="20dp"
android:orientation="vertical">
<com.futo.platformplayer.views.buttons.BigButton
android:id="@+id/button_import_profile"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:buttonText="@string/import_existing_profile"
app:buttonSubText="@string/use_an_existing_identity"
app:buttonIcon="@drawable/ic_arrow_downward"
android:layout_marginTop="8dp" />
</LinearLayout>
<com.futo.platformplayer.views.buttons.BigButton
android:id="@+id/button_new_profile"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:buttonIcon="@drawable/ic_person_add"
app:buttonSubText="@string/generate_a_new_identity"
app:buttonText="@string/new_profile" />
<com.futo.platformplayer.views.buttons.BigButton
android:id="@+id/button_import_profile"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:buttonIcon="@drawable/ic_arrow_downward"
app:buttonSubText="@string/use_an_existing_identity"
app:buttonText="@string/import_existing_profile" />
</LinearLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -65,6 +65,22 @@
app:layout_constraintTop_toBottomOf="@id/edit_profile_name"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<TextView
android:id="@+id/text_cta"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/inter_regular"
android:text="Further customize your profile, make platform claims, and other creator-specific features in the Harbor app.\n\nYou can export this profile to Harbor using the Export button."
android:textSize="12dp"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:textAlignment="center"
android:ellipsize="middle"
android:textColor="@color/gray_ac"
android:layout_marginTop="10dp"
app:layout_constraintTop_toBottomOf="@id/text_system"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<LinearLayout
android:id="@+id/layout_buttons"
@ -75,9 +91,18 @@
android:layout_marginEnd="20dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/edit_profile_name"
app:layout_constraintTop_toBottomOf="@id/text_cta"
app:layout_constraintBottom_toBottomOf="parent">
<com.futo.platformplayer.views.buttons.BigButton
android:id="@+id/button_open_harbor_profile"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:buttonText="Harbor Profile"
app:buttonSubText="See your Harbor profile in a browser"
app:buttonIcon="@drawable/ic_export"
android:layout_marginTop="8dp" />
<com.futo.platformplayer.views.buttons.BigButton
android:id="@+id/button_export"
android:layout_width="match_parent"